SpringCloud-Ribbon-03设计原理
Ribbon的核心是基于LoadBalancer负载均衡器来实现的,Ribbon通过ILoadBalancer接口对外提供统一的选择服务器(Server)的功能基础接口ILoadBalancer主要提供一下方法
public interface ILoadBalancer {
//向负载均衡器中维护的实例列表中,增加服务实例
public void addServers(List<Server> newServers);
//通过某种策略,从负载均衡器中挑选出具体的服务实例
public Server chooseServer(Object key);
//用来通知和标识负载均衡器中,某个具体的实例已经停止服务
public void markServerDown(Server server);
//获取当前服务的实例列表
public List<Server> getReachableServers();
//获取所有的服务实例列表,包括正常服务和停止服务的实例
public List<Server> getAllServers();
}
其中LoadBalancer内部有如下图的模块组成:
LoadBalancer模块图
ServerList模块
主要是负责维护server列表(新增,更新,删除),接口如下:
public interface ServerList<T extends Server> {
//获取初始化的服务列表
public List<T> getInitialListOfServers();
// 获取更新后的的服务列表
public List<T> getUpdatedListOfServers();
}
实现方式分以下两类,并可以通过<service-name>.ribbon.NIWSServerListClassName,来配置具体的实现方式
- 基于配置文件:通过配置文件,静态地配置服务器列表,可以使用netflix archaius框架动态监控配置文件的变化,来更新ServerList 信息,通过以下配置开启
<service name>.ribbon.NIWSServerListClassName=com.netflix.loadbalancer.ConfigurationBasedServerList
- 基于服务发现:结合服务发现组件如consul或eureka,实现动态更新服务列表,通过以下配置开启
<service name>.ribbon.NIWSServerListClassName=com.netflix.loadbalancer.DiscoveryEnabledNIWSServerList
ServerListUpdater模块
负责在运行时,动态的更新服务状态的方式,可以通过配置<service-name>.ribbon.ServerListUpdaterClassName设置,当前有如下两种实现方式:
- 基于定时任务的拉取
<service-name>.ribbon.ServerListUpdaterClassName=com.netflix.loadbalancer.PollingServerListUpdater
- 基于Eureka服务事件通知
<service-name>.ribbon.ServerListUpdaterClassName=com.netflix.loadbalancer.EurekaNotificationServerListUpdater
ribbon在默认情况下,会采用基于配置的服务列表维护,定时任务按时拉取服务列表的方式,频率为30s.
ServerListFilter模块
ServerListFilter的职能很简单,传入一个服务实例列表,过滤出满足过滤条件的服务列表
public interface ServerListFilter<T extends Server> {
public List<T> getFilteredListOfServers(List<T> servers);
}
ZoneAffinityServerListFilterRibbon:Ribbon 的默认ServerListFilter实现,采取了区域优先的过滤策略,与其相关的配置如下
# 是否开启区域优先,默认false
<service-name>.ribbon.EnableZoneAffinity=false
# 是否采取区域排他性,即只返回和当前Zone一致的服务实例
<service-name>.ribbon.EnableZoneExclusivity=false
ZonePreferenceServerListFilter:继承 ZoneAffinityServerListFilter,在其上增加了扩展,在其返回结果的基础上,再过滤出和本地服务相同区域(zone)的服务列表。
ServerListSubsetFilter:继承 ZoneAffinityServerListFilter,这个过滤器作用于当Server数量列表特别庞大时(比如有上百个Server实例),这时,长时间保持Http链接也不太合适,可以适当地保留部分服务,舍弃其中一些服务,这样可使释放没必要的链接。
ServerStats模块
ServerStats中记录这server的状态信息,如下
# 当前服务所属的可用区
zone
#总请求数量,client每次调用,数量会递增
totalRequests
#活动请求计数时间窗
activeRequestsCountTimeout
#连续连接失败计数
successiveConnectionFailureCount
#连接失败阈值通过属性
connectionFailureThreshold
#断路器超时因子
circuitTrippedTimeoutFactor
#最大断路器超时秒数
maxCircuitTrippedTimeout
#最后连接时间
lastAccessedTimestamp
#最后连接失败时间
lastConnectionFailedTimestamp
# 首次连接时间
firstConnectionTimestamp
....等其他信息
断路器:当有某个服务存在多个实例时,在请求的过程中,负载均衡器会统计每次请求的情况(请求相应时间,是否发生网络异常等),当出现了请求出现累计重试时,负载均衡器会标识当前服务实例,设置当前服务实例的断路的时间区间,在此区间内,当请求过来时,负载均衡器会将此服务实例从可用服务实例列表中暂时剔除,优先选择其他服务实例,可以通过以下参数设置断路器信息
# 连续连接失败计数
successiveConnectionFailureCount
#连接失败阈值,默认3超过则熔断
connectionFailureThreshold
#断路器超时因子
circuitTrippedTimeoutFactor
#最大断路器超时秒数
maxCircuitTrippedTimeout
....等其他信息
IPing ,IPingStrategy 接口
IPing用来检测Server是否可用,ILoadBalancer的实现类维护一个Timer每隔10s检测一次Server的可用状态,其核心方法有:
public interface IPing {
//检测服务是否存活
public boolean isAlive(Server server);
}
/**
* 定义Ping服务状态是否有效的策略,是序列化顺序Ping,还是并行的方式Ping,在此过程中,应当保证相互不受影响
*/
public interface IPingStrategy {
boolean[] pingServers(IPing ping, Server[] servers);
}
默认情况下,负载均衡器内部会创建一个周期性定时任务,检查server是否存活,相关配置参数如下
# Ping定时任务周期,默认30s
<service-name>.ribbon.NFLoadBalancerPingInterval=30
#Ping超时时间,默认2s
<service-name>.ribbon.NFLoadBalancerMaxTotalPingTime=2
# IPing实现类,Spring Cloud集成下的IPing实现:NIWSDiscoveryPing,
# 其使用Eureka作为服务注册和发现,则校验服务是否可用,则通过监听Eureka 服务更新来更新Ribbon的Server状态
<service-name>.ribbon.NFLoadBalancerPingClassName=
IRule 接口
IRule是负载均衡策略的抽象,ILoadBalancer通过调用IRule的choose()方法返回Server,其核心方法如下:
public interface IRule{
// 从负载均衡器中选择一个实例
public Server choose(Object key);
// 设置ILoadBalancer
public void setLoadBalancer(ILoadBalancer lb);
public ILoadBalancer getLoadBalancer();
}
以下是具体实现类,我们也可以自定义自己的负载均衡策略