Ribbon 基于restTemplate如何处理请求大致流程(二)

1.背景

在研究玩自动装配后,我搭了个demo,总共三个eureka server构成集群,然后两个服务提供者provider,一个consumer。在上一章简单了解自动装配的内容后,现在看看restTemplate是如何一步步走到ribbon的负载均衡器的。

// 这里是直接处理了默认的restTemplate
@Bean
@LoadBalanced
RestTemplate restTemplate(){
    return new RestTemplate();
}

@GetMapping("/hello2")
public String sayHelloWithProvider2(){
    String url = "http://ServiceProvider/provider/hello";
    return restTemplate.getForObject(url, String.class);
}


2.源码调试观测到LoadBalancerInterceptor

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jljaONCi-1623313193717)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d7a04304-ab76-4ef9-a1de-5959395dfa93/Untitled.png)]

上面找到了拦截器,下面就是进入拦截器了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yF3uW2Yn-1623313193720)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3d58245c-8668-405a-9abe-f4b05313172a/Untitled.png)]



3.LoadBalanceInterceptor到底在干啥?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xRJBrl9P-1623313193722)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b74d0867-f07f-424a-aa4e-627d79cb0171/Untitled.png)]
在LoadBalanceInterceptor中,
首先是获得了服务名ServiceProvider,
然后通过LoadBalanceRequestFactory的createRequest将HttpRequest,body,ClientHttpRequestExecution封装成LoadBalanceRequest。
最后进入了RibbonLoadBalancerClient进行ribbon相关的执行。

所以LoadBalancerInterceptor就是将请求进行封装,然后转换成LoadBalancerClient需要的类型。



4.RibbonLoadBalancerClient在干啥?

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
		// 选择负载均衡器,默认是DynamicServerLsitLoadBalancer
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
		// 通过loadBalancer选择服务
		Server server = getServer(loadBalancer, hint);
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}
		// 将获得的服务实例信息封装成RibbonServer
		RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
				serviceId), serverIntrospector(serviceId).getMetadata(server));
		// 拿着ribbonServer去处理请求
		return execute(serviceId, ribbonServer, request);
	}

在这里总结一下:

1.获取负载均衡器(getLoadBalancer

2.通过负载均衡器从服务列表中选择一个服务,这个服务将作为被发送的服务器。(getServer

  1. 执行请求 execute(serviceId, ribbonServer, request)

其实我们可以想象到,负载均衡器最关键的地方其实就是如何拿去到服务列表,然后如何从服务列表中选择服务。

所以后面会单独出一篇来讲,如何进行服务列表获取和服务选择。



5.RibbonLoadBalancerClient的execute又干了啥?

1.基于servcieId开启ribbon统计

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RhXVt0hc-1623313193727)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/5679c2fc-d328-4d40-b652-bafb70b52eae/Untitled.png)]

2.request.apply LoadBalanceRequest的匿名方法处理

org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory#createRequest

public LoadBalancerRequest<ClientHttpResponse> createRequest(final HttpRequest request,
			final byte[] body, final ClientHttpRequestExecution execution) {
		// 创建的LoadBalancerRequest自带一个方法apply,这里是匿名实现
		// 这里其实也在做如何将LoadBalancerRequest再封装成为HttpRequest,毕竟最后还是发http请求出去
		return instance -> {
						// 这里使用了一个ServiceRequestWrapper将服务实例信息和负载均衡器封装起来
            HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, loadBalancer);
            if (transformers != null) {
								// 这里可以通过自定义ServiceRequestWrapper来改变HttpRequest信息
                for (LoadBalancerRequestTransformer transformer : transformers) {
                    serviceRequest = transformer.transformRequest(serviceRequest, instance);
                }
            }
						// 这里就又走到了spring web 的http请求发送类去了,在这个方法中
						// 完成了 ServiceProvider到192.168.1.80:9955的服务名替换,后面就是正常的http发送流程了。
            return execution.execute(serviceRequest, body);
        };
	}


6.execution.execute在做啥?

在这里插入图片描述

其实它就是用来真正处理http请求的。这个包是spring-web包下的,其实是不存在跟ribbon相关的内容的。

Ribbon是如何将ServiceProvider这个服务名替换成IP+端口呢?

request.getURI()就是Ribbon完成转完的关键,Ribbon是通过继承HttpRequest,然后重写了getURI
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0W2tr6Vq-1623313193737)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7ed4ed4e-d873-4a60-9670-4abf5429d962/Untitled.png)]

没错,这就完成了服务名到ip和端口的替换。



7.小结

ribbon作为一个负载均衡工具,它拦截了requestTemplate,并做了一系列的操作来实现了通过服务名负载均衡访问其他服务。上面是整个拦截流程的大致过程,这里再总结一下。

  1. restTemplate按照自己执行流程进入InterceptingClientHttpRequest中,在这里发现了LoadBalancerInterceptor,并进入LoadBalancerInterceptor中的intercept方法
  2. 在intercept()方法中执行了LoadBalancerClient的execute方法,这个方法是负载均衡的核心
  3. execute方法中首先会获取负载均衡器ILoadBalancer,这个决定了到底从哪获取服务实例列表
  4. 然后通过getServer(loadBalancer,hint)方法获取服务实例列表并根据指定的Rule去计算出使用哪个服务实例
  5. 将服务实例包装到HttpRequest中(ServiceRequestWrapper就是HttpRequest和服务实例的包装)
  6. 通过重写getURI方法达到通过服务实例信息替换服务实例名到ip+端口的过程。

以上就是ribbon整个基于restTemplate运行的过程。这里我们看到有几个很重要的类或者接口:ILoadBalancer,LoadBalancerClient,LoadBalancerRequestFactory,ServiceRequestWrapper,IRule

这几个基本上应该算是整个ribbon的核心了。

后面几篇将针对这几个来进行详细解析。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值