前面提到的负载,其实就是由Ribbon实现。
当消费方发起请求时,先到Ribbon,然后Ribbon去到Eureka-server,拉取对应服务列表,然后根据负载策略,选择服务。
查看LoadBalancerInterceptor.java
实现了ClientHttpRequestInterceptor的intercept方法,代表会拦截客户请求的HTTP请求。
//拦截到RestTemplate发起的请求
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
URI originalUri = request.getURI();
//获取请求URL
String serviceName = originalUri.getHost();
//得到主机名也就服务名称
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
//loadBalancer.execute就是到Eureka拉取服务列表
}
查看到LoadBalancerClient是一个接口,而它的实现就有Ribbon
查看execut方法
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
//执行后得到一个DynamicServerListLoadBalance对象,动态服务列表均衡器,其属性allServerList就有服务列表信息,所以此步骤是去Eureka拉取服务
Server server = this.getServer(loadBalancer, hint);
//进行负载,查看getServer是调用了ZoneAwareLoadBalancer的chooseServer方法,进一步调用父类BaseLoadBalancer的chooseServer,执行了rule.choose()方法
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
} else {
RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
}
}
在父类BaseLoadBalancer中调用的以下方法
return this.rule.choose(key);
//从DynamicServerListLoadBalance中按规则选择一个
通过Ctrl+H,查看rule的实现类,有随机RandomRule和轮循RoundRobinRule,而默认是Zone
整体逻辑为:
- 消费方发起请求。
- 被LoadBalancerIntercepot负载均衡拦截器拦截。
- 拦截后交给RibbonLoadBanlanceClient。
- RibbonLoadBanlanceClient获取服务名称交给DynamicServerListLoadBalance处理
- DynamicServerListLoadBalance拉Eureka中拉取服务。
- 拉取到的服务根据Irule规则进行选择。
- 再将返回值返回给RibbonLoadBanlanceClient,最后由RibbonLoadBanlanceClient修改URL,发起请求。