Ribbon源码深度刨析-(2)核心组件:RibbonLoadBalancerClient

“不积跬步,无以至千里。”

接着上一篇文章,

return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));

显然微服务调用的逻辑都在这个LoadBalancerClient组件的execute方法中,那么这个组件是从哪里来的

@Bean
public LoadBalancerInterceptor ribbonInterceptor(
    LoadBalancerClient loadBalancerClient,
    LoadBalancerRequestFactory requestFactory) {
    return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}

可以发现,这个负责负载均衡的组件是在定义Bean的时候直接在形参中声明的,所以一定在一个地方注册到了spring的工厂

老规律,肯定是一个自动配置类

我直接告诉你得了,你去找我估计你要找到天荒地老

是一个叫RibbonAutoConfiguration的配置类中注册spring容器的

@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient() {
    return new RibbonLoadBalancerClient(springClientFactory());
}

而且这个配置类还加了一个限定,@AutoConfigureBefore,会在之前看的那个LoadBalancerAutoConfiguration之前来执行,因为两个有依赖关系,依赖的就是这个负载均衡组件RibbonLoadBalancerClient,明白了吧

@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})

也就是说,所有的微服务调用都会由RibbonLoadBalancerClient#execute方法来进行处理

现在来重点看看这个核心方法

@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    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);
}

把断点打在这个execute方法,使用浏览器发起请求,断点直接就进来了,可以看到此时已经获取到了服务Id,也就是服务名称

ribbonLoadBalancerClient.execute

getLoadBalancer(serviceId),这行代码是说,根据这个服务Id获取一个负载均衡组件ILoadBalancer,是一个DynamicServerListLoadBalancer,这一块是核心,会在下篇文章将获取这个组件的全流程进行刨析,这里先有个印象

DynamicServerListLoadBalancer

可以大致看一下这个负载均衡组件里面的信息

DynamicServerListLoadBalancer:{NFLoadBalancer:name=springboot-project-2,current list of Servers=[localhost:10001],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;	Instance count:1;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]
},Server stats: [[Server:localhost:10001;	Zone:defaultZone;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 08:00:00 CST 1970;	First connection made: Thu Jan 01 08:00:00 CST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@682278

current list of Servers=[localhost:10001],其实包含了被调服务的服务注册表,那么下面肯定有一个chooseServer之类的方法,从服务列表中,基于负载均衡算法,挑选出来一个server,发起http请求

getServer()

Server server = getServer(loadBalancer)

当然这个方法就是,传进去刚刚获取到的负载均衡组件,然后一定是基于其内部的一个Rule来从Server List中挑选一个Server,猜测

然后调用重载的execute方法,发起实际的http请求

public LoadBalancerRequest<ClientHttpResponse> createRequest(final HttpRequest request,
			final byte[] body, final ClientHttpRequestExecution execution) {
    return instance -> {
        HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, loadBalancer);
        if (transformers != null) {
            for (LoadBalancerRequestTransformer transformer : transformers) {
                serviceRequest = transformer.transformRequest(serviceRequest, instance);
            }
        }
        return execution.execute(serviceRequest, body);
    };
}

这个ClientHttpRequestExecution,实际就是调用spring原生的httpclient,发送http请求了

在这里插入图片描述

这里可以看到,在最终执行http请求的时候,服务名称已经替换成了ip:port的格式了,而且如果我们的被调服务如果部署在多台机器上面,那么这个ip会基于负载均衡组件内置的IRule组件来进行负载均衡的调用,最终拿到结果

response data

ok,总结一下

其实Ribbon主要的工作就是,

  1. 根据服务Id,也就是服务名称(被调服务),先拿到一个核心组件ILoadBalancer,这里面包含被调服务的Server List,服务列表
  2. 基于ILoadBalancer内置的IRule组件,负载均衡算法,从服务列表中挑选一个Server
  3. 基于Spring原生的http组件ClientHttpRequestExecution,发起http请求,最终拿到响应并返回,over!

后面的文章会重点分析一下,这个ILoadBalancer的初始化过程,以及如何里面的服务列表从哪里来的?其实想想也知道,肯定是跟Eureka进行整合,然后把Eureka本地缓存的服务注册表拿来用的,然后Eureka定时要从Server端更新自己的本地注册表,那么Ribbon肯定也要有这么个东西,来定时拉取最新的注册表之类的。。。

还有比较重要的就是ribbon是怎么从一堆服务中挑选出来每次要执行http请求的真正server的?

最后,附上一张手绘的ribbon大体的运行流程图吧,ribbon这个组件大体来说还是比较简单的

ribbon大体运行流程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值