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")@RefreshScopepublic 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")@RefreshScopepublic 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
三个服务:
5、关上浏览器拜访:http://127.0.0.1:8001/doc.html,点击Ribbon调用测试接口
菜单,进行测试,点击申请,咱们能够看到每次返回的端口都是变动的,一会儿是8001一会儿是8011,因为Ribbon负载平衡默认是应用的轮询策略
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公共负载平衡策略配置 */@Configurationpublic 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
本文源码在https://gitee.com/wmz1930/GitEgg的chapter-12分支。