Spring cloud

SpringCloud-Ribbon-03设计原理

2019-06-24  本文已影响11人  小亮__

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,来配置具体的实现方式

ServerListUpdater模块

负责在运行时,动态的更新服务状态的方式,可以通过配置<service-name>.ribbon.ServerListUpdaterClassName设置,当前有如下两种实现方式:

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();    
}

以下是具体实现类,我们也可以自定义自己的负载均衡策略


上一篇 下一篇

猜你喜欢

热点阅读