转载请注明出处:
1.什么是Ribbon
是 Netflix 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。在 SpringCloud 中, nacos一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从nacos中读 取到的服务信息,在调用服务节点提供的服务时,会合理(策略)的进行负载。 在SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的 列表信息,并基于内置的负载均衡算法,请求服务。
Ribbon的主要作用:基于Ribbon实现服务调用, 通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助 RestTemplate 最终进行调用负载均衡,当有多个服务提供者时,Ribbon可以根据负载均衡的算法自动的选择需要调用的服务地址
2. restTemplate 调用接口时使用Ribbon
首先需要定义 RestTemplate 使用 Ribbon 策略;
@LoadBalanced @Bean public RestTemplate restTemplate() { return new RestTemplate(); }
本地使用 RestTemplate 调用远程接口;
@Autowired private RestTemplate restTemplate; @RequestMapping(value = "/echo/{id}", method = RequestMethod.GET) public String echo(@PathVariable Long id) { return restTemplate.getForObject("http://member-service/member/get/" + id, String.class); }
3. Ribbon 原理
使用RestTemplate对象只需要访问一个带有对象名称的路径,也就是http://userservice/user/XX,就可以访问到相对应的接口,这其中离不开LoadBalancerInterceptor的帮助,它会去RestTemplate的请求进行拦截,然后从Eureka中获取服务id与端口号,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。
在LoadBalancerInterceptor这个类中,会有一个intercept方法,其拦截了用户的HttpRequest请求,通过调用以下api ;
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException { // 获取请求uri,也就是 http://user-service/user/8 URI originalUri = request.getURI(); // 获取uri路径的主机名,其实就是服务id,user-service String serviceName = originalUri.getHost(); Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri); // 处理服务id,和用户请求 return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution)); }
获取到了url、主机名、和服务的id,再将这些信息作为参数传到LoadBalancerClient(this.loadBalancer)的execute的方法中;
而在LoadBalancerClient的execute方法中可以通过服务id获取到服务列表,并获取合适的服务的端口号,这个方法的实现会进入到 RibbonLoadBalancerClient.execute 方法中;
- getLoadBalancer(serviceId):根据服务id获取ILoadBalancer,而ILoadBalancer会拿着服务id去eureka中获取服务列表并保存起来。
- getServer(loadBalancer):利用内置的负载均衡算法,从服务列表中选择一个。也就是127.0.0.1:8080
从这里可以知道,负载均衡的实现是在getServer方法中实现的
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
}
查看 loadBalancer.chooseServer 的实现,进入 BaseLoadBalancer 类
public Server chooseServer(Object key) { if (this.counter == null) { this.counter = this.createCounter(); } this.counter.increment(); if (this.rule == null) { return null; } else { try { return this.rule.choose(key); } catch (Exception var3) { logger.warn("LoadBalancer [{}]: Error choosing server for key {}", new Object[]{this.name, key, var3}); return null; } } }
从方法名中可以看出 rule.choose 为定义的负载均衡规则的选择,查看这个方法的实现:
通过快捷键查看该方法的实现类可以看到 项目中所支持的负载均衡规则;若打断点 可以发现,前面传过来的default对应的是RoundRobinRule对象 ; RoundRobinRule对应的是一个轮询的规则,所以这里采用的默认负载均衡规则是轮询;
集成了nacos 后,使用 NacosRule 规则进行负载均衡:
public Server choose(Object key) { try { String clusterName = this.nacosDiscoveryProperties.getClusterName(); String group = this.nacosDiscoveryProperties.getGroup(); DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer)this.getLoadBalancer(); String name = loadBalancer.getName(); // 根据group,name 等获取nacos 中的服务组 NamingService namingService = this.nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties()); // 获取服务组对应的所有实例信息:updateServiceNow 里面去调用 /instance/list接口查询服务信息 List<Instance> instances = namingService.selectInstances(name, group, true); if (CollectionUtils.isEmpty(instances)) { LOGGER.warn("no instance in service {}", name); return null; } else { List<Instance> instancesToChoose = instances; Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose); // 返回nacos的服务实例 return new NacosServer(instance); } } catch (Exception var10) { LOGGER.warn("NacosRule error", var10); return null; } }
4.常用的Ribbon负载均衡策略
内置负载均衡规则类 | 规则描述 |
RoundRobinRule | 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule | 对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit属性进行配置。 |
WeightedResponseTimeRule | 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 |
ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。 |
BestAvailableRule | 忽略那些短路的服务器,并选择并发数较低的服务器。 |
RandomRule | 随机选择一个可用的服务器。 |
RetryRule | 重试机制的选择逻辑 |
注意:nacos-discovery依赖了ribbon,可以不用再引入ribbon依赖
标签: spring cloud