微服务负载均衡器Ribbon和LoadBalancer 一、负载均衡介绍二、RibbonSpring Cloud Ribbon是基于Netflix Ribbon 实现的一套客户端的负载均衡工具Ribbon客户端组件提供一系列的完善的配置如超时重试等。通过Load Balancer获取到服务提供的所有机器实例Ribbon会自动基于某种规则(轮询随机)去调用这些服务。Ribbon也可以实现我们自己的负载均衡算法。.Spring Cloud Alibaba整合Ribbon服务调用者整合Ribbon1) 引入ribbon依赖!--添加ribbon的依赖-- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-netflix-ribbon/artifactId. /dependencynacos-discovery依赖了ribbon可以不用再引入ribbon依赖2) RestTemplate 添加LoadBalanced注解让RestTemplate在请求时拥有客户端负载均衡的能力Configuration public class RestConfig { Bean LoadBalanced //开启负载均衡 public RestTemplate restTemplate() { return new RestTemplate(); } }3使用微服务名发起调用Autowired private RestTemplate restTemplate; RequestMapping(value /findOrderByUserId/{id}) public R findOrderByUserId(PathVariable(id) Integer id) { // ribbon实现restTemplate需要添加LoadBalanced注解 String url http://mall-order/order/findOrderByUserId/id; R result restTemplate.getForObject(url,R.class); return result; }说明在RestTemplate的bean方法上加上LoadBalanced标识开启负载均衡同时会将服务名替换为ip:port的形式2.2 内核原理LoadBalanced 注解原理参考源码LoadBalancerAutoConfiguration。LoadBalanced使用了Qualifierspring中Qualifier用于筛选限定注入Bean。LoadBalanced利用Qualifier作为restTemplates注入的筛选条件筛选出具有负载均衡标识的RestTemplate。被LoadBalanced注解的restTemplate会被定制会被添加LoadBalancerInterceptor拦截器。因此如果不使用LoadBalanced注解也可以通过添加LoadBalancerInterceptor拦截器让restTemplate起到负载均衡器的作用如下Bean public RestTemplate restTemplate(LoadBalancerInterceptor loadBalancerInterceptor) { RestTemplate restTemplate new RestTemplate(); //注入loadBalancerInterceptor拦截器 restTemplate.setInterceptors(Arrays.asList(loadBalancerInterceptor)); return restTemplate; }2.3 Ribbon扩展功能2.3.Ribbon相关接口参考org.springframework.cloud.netflix.ribbon.RibbonClientConfigurationIClientConfigRibbon的客户端配置默认采用DefaultClientConfigImpl实现。IRuleRibbon的负载均衡策略默认采用ZoneAvoidanceRule实现该策略能够在多区域环境下选出最佳区域的实例进行访问。IPingRibbon的实例检查策略默认采用DummyPing实现该检查策略是一个特殊的实现实际上它并不会检查实例是否可用而是始终返回true默认认为所有服务实例都是可用的。ServerList服务实例清单的维护机制默认采用ConfigurationBasedServerList实现。ServerListFilter服务实例清单过滤机制默认采ZonePreferenceServerListFilter该策略能够优先过滤出与请求方处于同区域的服务实例。ILoadBalancer负载均衡器默认采用ZoneAwareLoadBalancer实现它具备了区域感知的能力。2.3.负载均衡策略对应的接口为IRule。RandomRule 随机选择一个Server。RetryRule 对选定的负载均衡策略机上重试机制在一个配置时间段内当选择Server不成功则一直尝试使用subRule的方式选择一个可用的server。RoundRobinRule 轮询选择 轮询index选择index对应位置的Server。AvailabilityFilteringRule 过滤掉一直连接失败的被标记为circuit tripped的后端Server并过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate来包含过滤server的逻辑其实就是检查status里记录的各个Server的运行状态。BestAvailableRule 选择一个最小的并发请求的Server逐个考察Server如果Server被tripped了则跳过。WeightedResponseTimeRule 根据响应时间加权响应时间越长权重越小被选中的可能性越低。ZoneAvoidanceRule 默认的负载均衡策略即复合判断Server所在区域的性能和Server的可用性选择Server在没有区域的环境下类似于轮询NacosRule:优先调用同一集群的实例基于随机权重。2.3.负载均衡策略配置全局配置调用的微服务一律使用指定的负载均衡策略Configuration public class RibbonConfig { /** * 全局配置 * 指定负载均衡策略 * return */ Bean public IRule ribbonRule() { // 指定使用Nacos提供的负载均衡策略优先调用同一集群的实例基于随机权重 return new NacosRule(); } 局部配置调用指定微服务时使用对应的负载均衡策略修改application.yml# 被调用的微服务名 mall-order: ribbon: # 指定使用Nacos提供的负载均衡策略优先调用同一集群的实例基于随机权重 NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule2.3.自定义负载均衡策略通过实现 IRule 接口可以自定义负载策略主要的选择服务逻辑在 choose 方法中。1实现基于Nacos权重的负载均衡策略Slf4j public class NacosRandomWithWeightRule extends AbstractLoadBalancerRule { Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; Override public Server choose(Object key) { DynamicServerListLoadBalancer loadBalancer (DynamicServerListLoadBalancer) getLoadBalancer(); String serviceName loadBalancer.getName(); NamingService namingService nacosDiscoveryProperties.namingServiceInstance(); try { //nacos基于权重的算法 Instance instance namingService.selectOneHealthyInstance(serviceName); return new NacosServer(instance); } catch (NacosException e) { log.error(获取服务实例异常{}, e.getMessage()); e.printStackTrace(); } return null; } Override public void initWithNiwsConfig(IClientConfig clientConfig) { } 2) 配置自定义的策略全局配置或局部配置2.3.饥饿加载在进行服务调用的时候如果网络情况不好第一次调用会超时。Ribbon默认懒加载意味着只有在发起调用的时候才会创建客户端。开启饥饿加载解决第一次调用慢的问题ribbon: eager-load: enabled: true clients: mall-order参数说明ribbon.eager-load.enabled开启ribbon的饥饿加载模式。ribbon.eager-load.clients指定需要饥饿加载的服务名也就是你需要调用的服务如果有多个服务则用逗号隔开。三、LoadBalancerSpring Cloud LoadBalancer是Spring Cloud官方自己提供的客户端负载均衡器, 用来替代Ribbon。Spring官方提供了RestTemplate和WebClient两种客户端都可以使用loadbalancer。RestTemplateRestTemplate是Spring提供的用于访问Rest服务的客户端RestTemplate提供了多种便捷访问远程Http服务的方法能够大大提高客户端的编写效率。默认情况下RestTemplate默认依赖jdk的HTTP连接工具。WebClientWebClient是从Spring WebFlux 5.0版本开始提供的一个非阻塞的基于响应式编程的进行Http请求的客户端工具。它的响应式编程的基于Reactor的。WebClient中提供了标准Http请求方式对应的get、post、put、delete等方法可以用来发起相应的请求。3.1 RestTemplate整合LoadBalancer1引入依赖!-- LoadBalancer -- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-loadbalancer/artifactId /dependency !-- 提供了RestTemplate支持 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- nacos服务注册与发现 移除ribbon支持-- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId exclusions exclusion groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-netflix-ribbon/artifactId /exclusion /exclusions /dependency注意nacos-discovery中引入了ribbon需要移除ribbon的包。如果不移除也可以在yml中配置不使用ribbon。默认情况下如果同时拥有RibbonLoadBalancerClient和BlockingLoadBalancerClient为了保持向后兼容性将使用RibbonLoadBalancerClient。要覆盖它可以设置spring.cloud.loadbalancer.ribbon.enabled属性为false。2使用LoadBalanced注解修饰RestTemplate开启客户端负载均衡功能Configuration public class RestConfig { Bean LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }3) 使用RestController RequestMapping(/user) public class UserController { Autowired private RestTemplate restTemplate; RequestMapping(value /findOrderByUserId/{id}) public R findOrderByUserId(PathVariable(id) Integer id) { String url http://mall-order/order/findOrderByUserId/id; R result restTemplate.getForObject(url,R.class); return result; } }3.2 WebClient整合LoadBalancer1引入依赖!-- LoadBalancer -- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-loadbalancer/artifactId /dependency !-- webflux -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-webflux/artifactId /dependency !-- nacos服务注册与发现 -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId exclusions exclusion groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-netflix-ribbon/artifactId /exclusion /exclusions /dependency2) 配置WebClient作为负载均衡器的clientConfiguration public class WebClientConfig { LoadBalanced Bean WebClient.Builder webClientBuilder() { return WebClient.builder(); } Bean WebClient webClient() { return webClientBuilder().build(); } }3) 使用Autowired private WebClient webClient; RequestMapping(value /findOrderByUserId2/{id}) public MonoR findOrderByUserIdWithWebClient(PathVariable(id) Integer id) { String url http://mall-order/order/findOrderByUserId/id; //基于WebClient MonoR result webClient.get().uri(url) .retrieve().bodyToMono(R.class); return result; }原理 底层会使用ReactiveLoadBalancer引入webFluxAutowired private ReactorLoadBalancerExchangeFilterFunction lbFunction; RequestMapping(value /findOrderByUserId3/{id}) public MonoR findOrderByUserIdWithWebFlux(PathVariable(id) Integer id) { String url http://mall-order/order/findOrderByUserId/id; //基于WebClientwebFlux MonoR result WebClient.builder() .filter(lbFunction) .build() .get() .uri(url) .retrieve() .bodyToMono(R.class); return result; }