微服务架构之均衡组件 Ribbon解析:LoadBalancerClient

举报
qingting-fly 发表于 2021/07/02 17:27:31 2021/07/02
【摘要】 Ribbon是一个可以管理Http和TCP客户端的客户端负载均衡器。Feign已经在使用Ribbon了,如果你使用过@FeignClient,那么Ribbon也会被使用。 Ribbon的核心思想就是named client,也就是带有名称的Ribbon Client。每个Client由可配置的组件构成,负责一类服务的调用请求。Spring Cloud通过RibbonClientConfigu...

Ribbon是一个可以管理Http和TCP客户端的客户端负载均衡器。Feign已经在使用Ribbon了,如果你使用过@FeignClient,那么Ribbon也会被使用。
Ribbon的核心思想就是named client,也就是带有名称的Ribbon Client。每个Client由可配置的组件构成,负责一类服务的调用请求。Spring Cloud通过RibbonClientConfiguration为每个named client创建一个ApplicationContext来进行组件装配。这些组件就包括ILoadBalancer,RestClientServerListFilter等。

LoadBalancerClient 实现解析

RibbonRestTemplateFeign之间的工作原理是阅读本文的基础。接下来,本文将会对LoadBalancerClient进行负载均衡的具体原理和实现。
LoadBalancerClientRibbon项目的核心类之一,可以在RestTemplate发送网络请求时替代RestTemplate进行网络调用。

/**
 * 客户端负载均衡器的接口
 */
public interface LoadBalancerClient extends ServiceInstanceChooser {

	/**
	 * 从serviceId所代表的服务列表中选择一个服务器来发送网络请求
	 */
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

	/**
     * 同上。
	 */
	<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;

	/**
     * 构建网络请求URI
	 */
	URI reconstructURI(ServiceInstance instance, URI original);
}

LoadBalancerClient接口继承了ServiceInstanceChooser
从服务器列表中依据负载均衡策略选出一个服务器。

//实现该类来选择一个服务器来发送请求。
public interface ServiceInstanceChooser {
    /**
     * 根据serviceId从服务器列表中选择一个ServiceInstance
     **/
    ServiceInstance choose(String serviceId);
}

RibbonLoadBalancerClientLoadBalancerClient的实现类之一,它的execute会首先使用ILoadBalancer来选择Server,然后将Server封装成RibbonServer对象,最后再调用LoadBalancerRequestapply函数进行网络请求的处理。

@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
    //每次发送请求都会创建一个ILoadBalancer,会涉及到选举规则(IRule),服务器列表集群(ServerList)和检验服务是否存在(IPing)等细节实现
    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    //选举一个具体的server,会涉及到选举规则,服务器列表和服务器是否存在等问题。
    Server server = getServer(loadBalancer);
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    }
    RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
            serviceId), serverIntrospector(serviceId).getMetadata(server));

    return execute(serviceId, ribbonServer, request);
}

ILoadBalancer的初始化过程,getLoadBalancer函数直接调用了SpringClientFactorygetLoadBalancer函数。SpringClientFactoryNamedContextFactory的实现类,关于NamedContextFactory的机制我们在Feign章节中已经详细讲解过了,通过它可以实现多套Bean实例的管理。

public ILoadBalancer getLoadBalancer(String name) {
		return getInstance(name, ILoadBalancer.class);
}

getServer则是直接调用了ILoadBalancerchooseServer函数来使用负载均衡策略从已知的服务器列表中选出一个服务器。

protected Server getServer(ILoadBalancer loadBalancer) {
    if (loadBalancer == null) {
        return null;
    }
    return loadBalancer.chooseServer("default");
}

execute函数中使用LoadBalancerRequest实例的apply函数,将之前根据负载均衡策略选择出来的服务器作为参数传递进去,进行真正的HTTP请求的发送。

public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
    Server server = null;
    if(serviceInstance instanceof RibbonServer) {
        server = ((RibbonServer)serviceInstance).getServer();
    }

    RibbonLoadBalancerContext context = this.clientFactory
            .getLoadBalancerContext(serviceId);
    RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);

    try {
        T returnVal = request.apply(serviceInstance);
        statsRecorder.recordStats(returnVal);
        return returnVal;
    }
    catch (IOException ex) {
        statsRecorder.recordStats(ex);
        throw ex;
    }
    catch (Exception ex) {
        statsRecorder.recordStats(ex);
        ReflectionUtils.rethrowRuntimeException(ex);
    }
    return null;
}

LoadBalancerRequestapply函数的具体实现本书不再详细讲解,因为Ribbon最为重要的部分就是使用负载均衡策略来选择服务器,也就是ILoadBalancerchooseServer函数的实现,本书会在接下来的小节里对其进行详细的讲解。

小结

当系统面临大量的用户访问,负载过高的时候,通常会使用增加服务器数量来进行横向扩展,多个服务器的负载需要均衡,以免有的服务器负载较大,而有的服务器负载较小。通过负载均衡,使得集群中的服务器的负载保持在稳定高效的状态,从而提高整个系统的处理能力。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。