版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29479041/article/details/83831533
一、简介
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源码
public class RibbonLoadBalancerClient implements LoadBalancerClient {
public ServiceInstance choose(String serviceId) {
return this.choose(serviceId, (Object)null);
}
public ServiceInstance choose(String serviceId, Object hint) {
Server server = this.getServer(this.getLoadBalancer(serviceId), hint);
return server == null ? null : new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
}
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
}
public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
//轮询规则
private static final IRule DEFAULT_RULE = new RoundRobinRule();
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;
}
}
}
//获取服务列表
public List<Server> getAllServers() {
//unmodifiableList不能修改的List
return Collections.unmodifiableList(this.allServerList);
}
public class ZoneAwareLoadBalancer<T extends Server> extends DynamicServerListLoadBalancer<T> {
public ZoneAwareLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping, ServerList<T> serverList, ServerListFilter<T> filter, ServerListUpdater serverListUpdater) {
super(clientConfig, rule, ping, serverList, filter, serverListUpdater);
}
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer {
public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping, ServerList<T> serverList, ServerListFilter<T> filter, ServerListUpdater serverListUpdater) {
super(clientConfig, rule, ping);
this.isSecure = false;
this.useTunnel = false;
this.serverListUpdateInProgress = new AtomicBoolean(false);
this.updateAction = new UpdateAction() {
public void doUpdate() {
DynamicServerListLoadBalancer.this.updateListOfServers();
}
};
this.serverListImpl = serverList;
this.filter = filter;
this.serverListUpdater = serverListUpdater;
if (filter instanceof AbstractServerListFilter) {
((AbstractServerListFilter)filter).setLoadBalancerStats(this.getLoadBalancerStats());
}
this.restOfInit(clientConfig);
}
public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
public BaseLoadBalancer(IClientConfig config, IRule rule, IPing ping) {
this.rule = DEFAULT_RULE;//轮询规则
this.pingStrategy = DEFAULT_PING_STRATEGY;
this.ping = null;
this.allServerList = Collections.synchronizedList(new ArrayList());
this.upServerList = Collections.synchronizedList(new ArrayList());
this.allServerLock = new ReentrantReadWriteLock();
this.upServerLock = new ReentrantReadWriteLock();
this.name = "default";
this.lbTimer = null;
this.pingIntervalSeconds = 10;
this.maxTotalPingTimeSeconds = 5;
this.serverComparator = new ServerComparator();
this.pingInProgress = new AtomicBoolean(false);
this.counter = Monitors.newCounter("LoadBalancer_ChooseServer");
this.enablePrimingConnections = false;
this.changeListeners = new CopyOnWriteArrayList();
this.serverStatusListeners = new CopyOnWriteArrayList();
this.initWithConfig(config, rule, ping);
}
三、自定义负载均衡策略
spring:
application:
name: order
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://localhost:3306/SpringCloud_Sell?characterEncoding=utf-8&useSSL=false
jpa:
show-sql: true
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
server:
port: 8866
#自定义负载均衡规则
PRODUCT:
ribbon:
#随机规则
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule