Spring Cloud Ribbon 全解 (2) - 基本组件简介

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
简介: Spring Cloud Ribbon 全解 (2) - 基本组件简介

本文基于SpringCloud-Dalston.SR5

对于一个负载均衡器,就是以用户请求为输入,请求响应为输出的代理模块。


image.png


这个模块基本上就是包括一个服务实例列表,根据请求还有负载均衡规则选择一个合适的实例来执行请求并返回响应。


image.png


这个服务实例列表,一般包含每个实例基本信息,然后还有,这个实例相关的负载均衡统计信息(例如请求失败多少次,有多少正在处理的请求等等,用于实例过滤和负载均衡规则选择Server)


image.png


再深入些,我们需要获取和更新这个服务列表(一般是从注册中心或者配置中获取),有时候我们还要根据一些规则过滤掉某些服务实例不参与负载均衡,同时,我们可能还需要与每个服务实例维持心跳来保证服务实例是可用的(虽然注册中心中也可以体现,但是心跳能更准确迅速地排除故障实例,减少响应时间)。


image.png


接下来,我们来看一下Ribbon的主要元素(先不仔细看实现),和上面的负载均衡器组成对应起来

  1. 所有Ribbon负载均衡器需要实现的接口IClient
  2. 服务实例列表维护机制实现的接口ServerList
  3. 负载均衡数据记录LoadBalancerStats
  4. 负责选取Server的接口ILoadBalancer
  5. 负载均衡选取规则实现的接口IRule
  6. 检查实例是否存活实现的接口IPing
  7. 服务实例列表更新机制实现的接口ServerListUpdater
  8. 服务实例列表过滤机制ServerListFilter


1. 所有Ribbon负载均衡器需要实现的接口IClient


IClient.java

public interface IClient<S extends ClientRequest, T extends IResponse> {
  /**
   * Execute the request and return the response. It is expected that there is no retry and all exceptions are thrown directly.
   */
    public T execute(S request, IClientConfig requestConfig) throws Exception; 
}

负载均衡器执行一个ClientRequest,并返回一个IResponse。注意,execute方法直接抛出所有异常,并且重试逻辑并不在实现execute的方法里面。而且,可以看出execute方法并没有指定通信协议,在SpringCloud环境下,通信协议是HTTP或者HTTPS

基本上Ribbon中可以被配置的元素,都是用IClientConfig这个类作为配置类。这里不详细分析源码,如果用到了其中的配置,我们会仔细分析其中的配置以及原理。默认实现是DefaultClientConfigImpl,其中每个配置都是基于Spring家族的Archaius实现的动态配置


ClientRequest.java

public class ClientRequest implements Cloneable {
    protected URI uri;
    protected Object loadBalancerKey = null;
    protected Boolean isRetriable = null;
    protected IClientConfig overrideConfig;
    //构造器和getter、setter省略
}

其中uri是请求需要发送到的uri地址;loadBalancerKey用于选择服务实例,即用作后面我们会提到的这个方法ILoadBalancer.chooseServer(Object key)的参数;isRetriable代表这个请求是否可以被重试;overrideConfig是请求相关的一些配置。


IResponse.java

public interface IResponse extends Closeable
{
   /**
    * Returns the raw entity if available from the response 
    */
   public Object getPayload() throws ClientException;
   /**
    * A "peek" kinda API. Use to check if your service returned a response with an Entity
    */
   public boolean hasPayload();
   /**
    * @return true if the response is deemed success, for example, 200 response code for http protocol.
    */
   public boolean isSuccess();
   /**
    * Return the Request URI that generated this response
    */
   public URI getRequestedURI();
   /**
    * 
    * @return Headers if any in the response.
    */
   public Map<String, ?> getHeaders();   
}

其实这个的实现类也会包含执行器逻辑,例如重试和异常处理等等


2. 服务实例列表维护机制实现的接口ServerList


public interface ServerList<T extends Server> {
    public List<T> getInitialListOfServers();
    public List<T> getUpdatedListOfServers();   
}

这个接口定义了如何更新并维护实例列表,getInitialListOfServers定义如何初次获取服务实例列表,getUpdatedListOfServers如何获取服务实例列表的更新


3. 负载均衡数据记录LoadBalancerStats


public class LoadBalancerStats {
    String name;
    //zone相关信息,默认用不到
    volatile Map<String, ZoneStats> zoneStatsMap = new ConcurrentHashMap<String, ZoneStats>();
    volatile Map<String, List<? extends Server>> upServerListZoneMap = new ConcurrentHashMap<String, List<? extends Server>>();
    //动态配置,连接失败上限
    private volatile DynamicIntProperty connectionFailureThreshold;
    //动态配置,熔断时间因子
    private volatile DynamicIntProperty circuitTrippedTimeoutFactor;
    //动态配置,最大熔断时间
    private volatile DynamicIntProperty maxCircuitTrippedTimeout;
    //动态配置,每个Server负载均衡统计数据过期时间配置
    private static final DynamicIntProperty SERVERSTATS_EXPIRE_MINUTES = 
        DynamicPropertyFactory.getInstance().getIntProperty("niws.loadbalancer.serverStats.expire.minutes", 30);
    //每个Server的负载均衡统计数据
    private final LoadingCache<Server, ServerStats> serverStatsCache = 
        CacheBuilder.newBuilder()
            .expireAfterAccess(SERVERSTATS_EXPIRE_MINUTES.get(), TimeUnit.MINUTES)
            .removalListener(new RemovalListener<Server, ServerStats>() {
                @Override
                public void onRemoval(RemovalNotification<Server, ServerStats> notification) {
                    notification.getValue().close();
                }
            })
            .build(
                new CacheLoader<Server, ServerStats>() {
                    public ServerStats load(Server server) {
                        return createServerStats(server);
                    }
                });
}


4. 负责选取Server的接口ILoadBalancer


ILoadBalancer.java

public interface ILoadBalancer {
  public void addServers(List<Server> newServers);
  public Server chooseServer(Object key);
  public void markServerDown(Server server);
  public List<Server> getServerList(boolean availableOnly);
}

addServers用来添加可以用来执行请求的Server;chooseServer根据传入的参数,结合某些负载均衡规则,返回某个Server;markServerDown用来标记某个Server为DOWN状态,这样一般下次调用chooseServer就不会选取这个Server;getServerList用来获取所有Server列表


Server.java

public class Server {
    public static final String UNKNOWN_ZONE = "UNKNOWN";
    String host;
    int port = 80;
    String id;
    boolean isAliveFlag;
    private String zone = UNKNOWN_ZONE;
    private volatile boolean readyToServe = true;
    //getter和setter省略
}

host和port代表实例提供服务的的ip和端口。id唯一标识这个Server,isAliveFlag标识这个Server是否还活着;zone代表所在区域


5. 负载均衡选取规则实现的接口IRule


public interface IRule{
    public Server choose(Object key);
    public void setLoadBalancer(ILoadBalancer lb);
    public ILoadBalancer getLoadBalancer();    
}

choose方法是根据key选择Server;setLoadBalancer和getLoadBalancer是设置相应的ILoadBalancer


6. 检查实例是否存活实现的接口IPing


public interface IPing {
    public boolean isAlive(Server server);
}

isAlive方法判断Server是否存活


7. 服务实例列表更新机制实现的接口ServerListUpdater


public interface ServerListUpdater {
    //定义了更新服务实例列表的操作doUpdate
    public interface UpdateAction {
        void doUpdate();
    }
    //开始调度更新服务实例列表,可以看到这里以UpdateAction为传参
    void start(UpdateAction updateAction);
    //停止更新服务实例列表
    void stop();
    //上次服务实例列表更新时间
    String getLastUpdate();
    //上次服务实例列表更新时间间隔
    long getDurationSinceLastUpdateMs();
    //已经错过几轮更新
    int getNumberMissedCycles();
    //使用线程池大小
    int getCoreThreads();
}

这个接口定义了如何更新服务实例列表


8. 服务实例列表过滤机制ServerListFilter


public interface ServerListFilter<T extends Server> {
    public List<T> getFilteredListOfServers(List<T> servers);
}

这个接口定义了如何过滤出需要的服务实例列表

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
1月前
|
消息中间件 监控 Java
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
36 6
|
1月前
|
Java 关系型数据库 MySQL
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
58 5
|
1月前
|
缓存 监控 Java
如何将Spring Boot应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot应用程序部署到Pivotal Cloud Foundry (PCF)
41 5
|
2月前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
114 5
|
1月前
|
负载均衡 Java Nacos
常见的Ribbon/Spring LoadBalancer的负载均衡策略
自SpringCloud 2020版起,Ribbon被弃用,转而使用Spring Cloud LoadBalancer。Ribbon支持轮询、随机、加权响应时间和重试等负载均衡策略;而Spring Cloud LoadBalancer则提供轮询、随机及Nacos负载均衡策略,基于Reactor实现,更高效灵活。
79 0
|
4月前
|
XML 缓存 Java
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
66 10
|
4月前
|
XML 存储 Java
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
|
5月前
|
人工智能 自然语言处理 Java
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
文章介绍了Spring AI,这是Spring团队开发的新组件,旨在为Java开发者提供易于集成的人工智能API,包括机器学习、自然语言处理和图像识别等功能,并通过实际代码示例展示了如何快速集成和使用这些AI技术。
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
|
5月前
|
Java 开发工具 Spring
【Azure 事件中心】azure-spring-cloud-stream-binder-eventhubs客户端组件问题, 实践消息非顺序可达
【Azure 事件中心】azure-spring-cloud-stream-binder-eventhubs客户端组件问题, 实践消息非顺序可达
|
缓存 负载均衡 监控
Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul
Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul
1371 0