八、SpringCloud之负载均衡器Ribbon

一、简介

1、Ribbon

Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,RestTemplate、Feign、Zuul等都是使用了Ribbon。

2、Ribbon实现软负载均衡核心

  • 服务发现(发现依赖服务的列表,依据服务的名字,把该服务下所有的实例都找出来)
  • 服务选择规则(依据规则策略,如何从多个服务中选择一个有效的服务)
  • 服务监听(检测失效的服务,做到高效剔除)

3、Ribbon主要组件

通过ServerList获取所有可用服务列表,然后通过ServerListFilter过滤掉一部分地址,最后在剩下的地址中,通过IRule选择一个实例作为最终目标结果。

  • ServerList
  • IRule
  • ServerListFilter

二、追踪Ribbon源码

1 2public class RibbonLoadBalancerClient implements LoadBalancerClient { 3 4 public ServiceInstance choose(String serviceId) { 5 return this.choose(serviceId, (Object)null); 6 } 7 8 public ServiceInstance choose(String serviceId, Object hint) { 9 Server server = this.getServer(this.getLoadBalancer(serviceId), hint); 10 return server == null ? null : new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server)); 11 } 12 13 protected Server getServer(ILoadBalancer loadBalancer, Object hint) { 14 return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default"); 15 } 16
1public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware { 2 //轮询规则 3 private static final IRule DEFAULT_RULE = new RoundRobinRule(); 4 public Server chooseServer(Object key) { 5 if (this.counter == null) { 6 this.counter = this.createCounter(); 7 } 8 9 this.counter.increment(); 10 if (this.rule == null) { 11 return null; 12 } else { 13 try { 14 return this.rule.choose(key); 15 } catch (Exception var3) { 16 logger.warn("LoadBalancer [{}]: Error choosing server for key {}", new Object[]{this.name, key, var3}); 17 return null; 18 } 19 } 20 } 21 22 //获取服务列表 23 public List<Server> getAllServers() { 24 //unmodifiableList不能修改的List 25 return Collections.unmodifiableList(this.allServerList); 26 } 27 28
1public class ZoneAwareLoadBalancer<T extends Server> extends DynamicServerListLoadBalancer<T> { 2 3 public ZoneAwareLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping, ServerList<T> serverList, ServerListFilter<T> filter, ServerListUpdater serverListUpdater) { 4 super(clientConfig, rule, ping, serverList, filter, serverListUpdater); 5 } 6
1public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer { 2 3 public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping, ServerList<T> serverList, ServerListFilter<T> filter, ServerListUpdater serverListUpdater) { 4 super(clientConfig, rule, ping); 5 this.isSecure = false; 6 this.useTunnel = false; 7 this.serverListUpdateInProgress = new AtomicBoolean(false); 8 this.updateAction = new UpdateAction() { 9 public void doUpdate() { 10 DynamicServerListLoadBalancer.this.updateListOfServers(); 11 } 12 }; 13 this.serverListImpl = serverList; 14 this.filter = filter; 15 this.serverListUpdater = serverListUpdater; 16 if (filter instanceof AbstractServerListFilter) { 17 ((AbstractServerListFilter)filter).setLoadBalancerStats(this.getLoadBalancerStats()); 18 } 19 20 this.restOfInit(clientConfig); 21 } 22
1public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware { 2 3 public BaseLoadBalancer(IClientConfig config, IRule rule, IPing ping) { 4 this.rule = DEFAULT_RULE;//轮询规则 5 this.pingStrategy = DEFAULT_PING_STRATEGY; 6 this.ping = null; 7 this.allServerList = Collections.synchronizedList(new ArrayList()); 8 this.upServerList = Collections.synchronizedList(new ArrayList()); 9 this.allServerLock = new ReentrantReadWriteLock(); 10 this.upServerLock = new ReentrantReadWriteLock(); 11 this.name = "default"; 12 this.lbTimer = null; 13 this.pingIntervalSeconds = 10; 14 this.maxTotalPingTimeSeconds = 5; 15 this.serverComparator = new ServerComparator(); 16 this.pingInProgress = new AtomicBoolean(false); 17 this.counter = Monitors.newCounter("LoadBalancer_ChooseServer"); 18 this.enablePrimingConnections = false; 19 this.changeListeners = new CopyOnWriteArrayList(); 20 this.serverStatusListeners = new CopyOnWriteArrayList(); 21 this.initWithConfig(config, rule, ping); 22 } 23

三、自定义负载均衡策略

1spring: 2 application: 3 name: order 4 datasource: 5 driver-class-name: com.mysql.jdbc.Driver 6 username: root 7 password: 123456 8 url: jdbc:mysql://localhost:3306/SpringCloud_Sell?characterEncoding=utf-8&useSSL=false 9 jpa: 10 show-sql: true 11eureka: 12 client: 13 service-url: 14 defaultZone: http://localhost:8761/eureka/ 15server: 16 port: 8866 17#自定义负载均衡规则 18PRODUCT: 19 ribbon: 20 #随机规则 21 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule 22 23

 

代码交流 2021