SpringCloud微服务实战——搭建企业级开发框架(十二):OpenFeign+Ribbon实现负载均衡

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: Ribbon是Netflix下的负载均衡项目,它主要实现中间层应用程序的负载均衡。为Ribbon配置服务提供者地址列表后,Ribbon就会基于某种负载均衡算法,自动帮助服务调用者去请求。Ribbon默认提供的负载均衡算法有多种,例如轮询、随即、加权轮训等,也可以为Ribbon实现自定义的负载均衡算法。Ribbon有以下特性:

 Ribbon是Netflix下的负载均衡项目,它主要实现中间层应用程序的负载均衡。为Ribbon配置服务提供者地址列表后,Ribbon就会基于某种负载均衡算法,自动帮助服务调用者去请求。Ribbon默认提供的负载均衡算法有多种,例如轮询、随即、加权轮训等,也可以为Ribbon实现自定义的负载均衡算法。


Ribbon有以下特性:


  • 负载均衡器,可支持插拔式的负载均衡规则


  • 对多种协议提供支持,如HTTP、TCP、UDP


  • 集成了负载均衡功能的客户端


Feign利用Ribbon实现负载均衡的过程:


  • 通过在启动类加@EnableFeignCleints注解开启FeignCleint


  • 根据Feign的规则实现接口,并加在接口定义处添加@FeignCleint注解


  • 服务启动后,扫描带有@ FeignCleint的注解的类,并将这些信息注入到ioc容器中


  • 当接口的方法被调用,通过jdk的代理,来生成具体的RequesTemplate


  • RequesTemplate再生成Request


  • Request交给Client去处理,其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp


    最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡。


  OpenFeign 中使用 Ribbon 进行负载均衡,所以 OpenFeign 直接内置了 Ribbon。在导入OpenFeign 依赖后,无需再专门导入 Ribbon 依赖。接下来,我们把gitegg-service-base作为服务的调用方,启动两个不同端口的gitegg-service-system作为服务的被调用方,测试Ribbon的负载均衡。


1、首先在gitegg-service-system工程中,新建被调用的controller方法,返回系统配置的端口号以区分是哪个服务被调用了。


package com.gitegg.service.system.controller;
import com.gitegg.platform.boot.common.base.Result;
import com.gitegg.service.system.dto.SystemDTO;
import com.gitegg.service.system.service.ISystemService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping(value = "system")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Api(tags = "gitegg-system")
@RefreshScope
public class SystemController {
    private final ISystemService systemService;
    @Value("${spring.datasource.maxActive}")
    private String nacosMaxActiveType;
    @Value("${server.port}")
    private Integer serverPort;
    @GetMapping(value = "list")
    @ApiOperation(value = "system list接口")
    public Object list() {
        return systemService.list();
    }
    @GetMapping(value = "page")
    @ApiOperation(value = "system page接口")
    public Object page() {
        return systemService.page();
    }
    @GetMapping(value = "exception")
    @ApiOperation(value = "自定义异常及返回测试接口")
    public Result<String> exception() {
        return Result.data(systemService.exception());
    }
    @PostMapping(value = "valid")
    @ApiOperation(value = "参数校验测试接口")
    public Result<SystemDTO> valid(@Valid @RequestBody SystemDTO systemDTO) {
        return Result.data(systemDTO);
    }
    @PostMapping(value = "nacos")
    @ApiOperation(value = "Nacos读取配置文件测试接口")
    public Result<String> nacos() {
        return Result.data(nacosMaxActiveType);
    }
    @GetMapping(value = "api/by/id")
    @ApiOperation(value = "Fegin Get调用测试接口")
    public Result<Object> feginById(@RequestParam("id") String id) {
        return Result.data(systemService.list());
    }
    @PostMapping(value = "api/by/dto")
    @ApiOperation(value = "Fegin Post调用测试接口")
    public Result<Object> feginByDto(@Valid @RequestBody SystemDTO systemDTO) {
        return Result.data(systemDTO);
    }
    @GetMapping("/api/ribbon")
    @ApiOperation(value = "Ribbon调用测试接口")
    public Result<String> testRibbon() {
        return Result.data("现在访问的服务端口是:" + serverPort);
    }
}


2、在gitegg-service-system-api工程中,编写使用OpenFeign调用testRibbon的公共方法


package com.gitegg.service.system.api.feign;
import com.gitegg.platform.boot.common.base.Result;
import com.gitegg.service.system.api.dto.ApiSystemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "gitegg-service-system")
public interface ISystemFeign {
    /**
     * OpenFeign测试Get
     *
     * @param id
     * @return
     */
    @GetMapping("/system/api/by/id")
    Result<Object> querySystemById(@RequestParam("id") Long id);
    /**
     * OpenFeign测试Post
     *
     * @param apiSystemDTO
     * @return ApiSystemDTO
     */
    @PostMapping("/system/api/by/dto")
    Result<ApiSystemDTO> querySystemByDto(@RequestBody ApiSystemDTO apiSystemDTO);
    /**
     * OpenFeign测试Ribbon负载均衡功能
     * @return
     */
    @GetMapping("/system/api/ribbon")
    Result<String> testRibbon();
}


3、在gitegg-service-base中添加测试Ribbon负载均衡的Feign调用方法


package com.gitegg.service.base.controller;
import com.gitegg.platform.boot.common.base.Result;
import com.gitegg.service.system.api.dto.ApiSystemDTO;
import com.gitegg.service.system.api.feign.ISystemFeign;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping(value = "base")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Api(tags = "gitegg-base")
@RefreshScope
public class BaseController {
    private final ISystemFeign systemFeign;
    @GetMapping(value = "api/by/id")
    @ApiOperation(value = "Fegin Get调用测试接口")
    public Result<Object> feginById(@RequestParam("id") Long id) {
        return Result.data(systemFeign.querySystemById(id));
    }
    @PostMapping(value = "api/by/dto")
    @ApiOperation(value = "Fegin Post调用测试接口")
    public Result<Object> feginByDto(@Valid @RequestBody ApiSystemDTO systemDTO) {
        return Result.data(systemFeign.querySystemByDto(systemDTO));
    }
    @PostMapping(value = "api/ribbon")
    @ApiOperation(value = "Ribbon调用测试接口")
    public Result<Object> testRibbon() {
        return Result.data(systemFeign.testRibbon());
    }
}


4、先启动gitegg-service-base服务,再启动gitegg-service-system服务,服务启动成功之后,将gitegg-service-system下bootstrap.yml里面server.port改为8011,然后再点击启动,这样就启动了两个gitegg-service-system服务(如果运行两个服务时提示:gitegg-service-system is not allowed to run in parallel. Would you like to stop the running one?,这时,在IDEA中点击Run-Edit configurations-勾选Allow parallel run即可),服务全部启动完毕之后,可以在Console窗口里面看到三个服务的Console


微信图片_20220518092801.png

image.png


三个服务:


微信图片_20220518092804.png

image.png


5、打开浏览器访问:http://127.0.0.1:8001/doc.html,点击Ribbon调用测试接口

菜单,进行测试,点击请求,我们可以看到每次返回的端口都是变化的,一会儿是8001一会儿是8011,因为Ribbon负载均衡默认是使用的轮询策略


微信图片_20220518092808.png

image.png


微信图片_20220518092811.png

image.png


6、如果我们需要修改负载均衡策略或者自定义负载均衡策略,根据我们的架构设计,我们在GitEgg-Platform的子工程gitegg-platform-cloud中设置公共的负载均衡策略,然后每个微服务需要不同的策略的话,可以在自己的工程中添加配置文件。接下来,在gitegg-platform-cloud中新建Ribbon配置类


package com.gitegg.platform.cloud.ribbon.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @Description Ribbon公共负载均衡策略配置
 */
@Configuration
public class RibbonConfig {
    /**
     * 负载均衡策略配置
     * @return
     */
    @Bean
    public IRule rule(){
        //随机策略  从所有可用的提供者中随机选择一个
        return new RandomRule();
    }
}


7、修改完成之后,GitEgg_Platform工程重新执行install,GitEgg_Cloud刷新导入的包,参照步骤5再执行测试,这时我们发现微服务返回的端口,不再是有规律的切换,而是随机不确定的出现。


注意:


这里RibbonConfig只用于测试负载均衡策略,请不要在生产环境中这样使用,否则会出现问题:在微服务A中调用微服务B和微服务C,然后再调用微服务B,这是RibbonLoadBalancerClient在获取微服务时,渠到的serviceId为null,就会获取到上次的微服务,进而导致404错误。因为OpenFeign默认使用的是Ribbon提供的负载均衡策略,我们在实际应用中可以选择Nacos提供的NacosRule策略,利用Nacos权重进行负载均衡:


#负载均衡策略
  NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
相关文章
|
负载均衡 算法 Java
Spring Cloud全解析:负载均衡算法
本文介绍了负载均衡的两种方式:集中式负载均衡和进程内负载均衡,以及常见的负载均衡算法,包括轮询、随机、源地址哈希、加权轮询、加权随机和最小连接数等方法,帮助读者更好地理解和应用负载均衡技术。
573 2
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
1062 3
|
人工智能 数据可视化 JavaScript
颠覆开发效率!国内首个微服务编排框架Juggle开源啦!
Juggle是国内首个开源的微服务编排框架,专注于解决企业微服务进程中接口重复开发、系统对接复杂等问题。它提供零代码、低代码和AI增强功能,通过可视化拖拽快速组装简单API为复杂接口,支持多协议、多语言脚本和流程多版本管理。相比国外框架如Conductor,Juggle更贴合国内需求,具备高效开发、企业级可靠性及信创适配等优势,助力企业实现敏捷创新与数字化转型。
1148 0
颠覆开发效率!国内首个微服务编排框架Juggle开源啦!
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
1504 61
|
负载均衡 Dubbo 应用服务中间件
框架巨擘:Dubbo如何一统异构微服务江湖,成为开发者的超级武器!
【8月更文挑战第8天】在软件开发中,微服务架构因灵活性和可扩展性备受欢迎。面对异构微服务的挑战,Apache Dubbo作为高性能Java RPC框架脱颖而出。它具备服务注册与发现、负载均衡及容错机制等核心特性,支持多种通信协议和序列化方式,能有效连接不同技术栈的微服务。Dubbo的插件化设计保证了面向未来的扩展性,使其成为构建稳定高效分布式系统的理想选择。
424 80
|
Dubbo Java 应用服务中间件
微服务框架Dubbo环境部署实战
微服务框架Dubbo环境部署的实战指南,涵盖了Dubbo的概述、服务部署、以及Dubbo web管理页面的部署,旨在指导读者如何搭建和使用Dubbo框架。
1348 17
微服务框架Dubbo环境部署实战
|
负载均衡 Java 持续交付
深入解析微服务架构中的服务发现与负载均衡
深入解析微服务架构中的服务发现与负载均衡
896 7
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
存储 设计模式 缓存
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
该文章主要介绍了如何在OpenFeign中集成Ribbon以实现负载均衡,并详细分析了Ribbon中服务选择和服务过滤的核心实现过程。文章还涉及了Ribbon中负载均衡器(ILoadBalancer)和负载均衡策略(IRule)的初始化方式。
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现