2.1SpringCloud学习之-Ribbon源码学习

104 阅读2分钟

1.背景

今天我们学习SpringCloud的客户端负载均衡Ribbon

我们今天继续使用之前eureka-server作为服务注册中心

使用Springboot和springcloud的版本如下

  • springboot版本:2.3.5-release
  • springcloud版本:Hoxton.SR9

2.源码解析

@LoadBalanced

  @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

RestTemplate

@RequestMapping("/api/comsumer/user")
@RestController
public class UserController {

    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/{id}")
    public String selectUser(@PathVariable("id") String id){
        ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://ms-ribbon-producer/api/user/{id}",String.class,id);
        return responseEntity.getBody();
    }
}

通过消费者,我们看到我们使用RestTemplate,这个如何使用ribbon的呢?

2.1分析RestTemplate

protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
			@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {

		ClientHttpResponse response = null;
		try {
		 //特别重要。创建请求
			ClientHttpRequest request = createRequest(url, method);
			if (requestCallback != null) {
				requestCallback.doWithRequest(request);
			}
			//特别重要。执行请求
			response = request.execute();
			handleResponse(url, method, response);
			return (responseExtractor != null ? responseExtractor.extractData(response) : null);
		}
		finally {
			if (response != null) {
				response.close();
			}
		}
	}

org.springframework.http.client.AbstractClientHttpRequest#execute

	@Override
	public final ClientHttpResponse execute() throws IOException {
		assertNotExecuted();
		////特别重要。执行请求
		ClientHttpResponse result = executeInternal(this.headers);
		this.executed = true;
		return result;
	}

org.springframework.http.client.AbstractBufferingClientHttpRequest#executeInternal(org.springframework.http.HttpHeaders

@Override
	protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
		byte[] bytes = this.bufferedOutput.toByteArray();
		if (headers.getContentLength() < 0) {
			headers.setContentLength(bytes.length);
		}
		////特别重要。执行请求
		ClientHttpResponse result = executeInternal(headers, bytes);
		this.bufferedOutput = new ByteArrayOutputStream(0);
		return result;
	}

org.springframework.http.client.InterceptingClientHttpRequest#executeInternal

	@Override
	protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
		InterceptingRequestExecution requestExecution = new InterceptingRequestExecution();
			////特别重要。执行请求
		return requestExecution.execute(this, bufferedOutput);
	}
	@Override
		public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
		////特别重要。执行拦截器
			if (this.iterator.hasNext()) {
				ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
				return nextInterceptor.intercept(request, body, this);
			}
		
		}

org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor#intercept

	@Override
	public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) throws IOException {
		final URI originalUri = request.getURI();
		String serviceName = originalUri.getHost();
		//this.loadBalancer =RibbonLoadBalancerClient
		return this.loadBalancer.execute(serviceName,
				this.requestFactory.createRequest(request, body, execution));
	}

org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient#execute

	public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
			throws IOException {
			//获取负载均衡器
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
			//获取服务
		Server server = getServer(loadBalancer, hint);
		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);
	}

org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient#getServer 获取对应的服务器

protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
	if (loadBalancer == null) {
		return null;
	}
	// Use 'default' on a null hint, or just pass it on?
	//特别重要:通过负载均衡器来寻找对应的服务
	return loadBalancer.chooseServer(hint != null ? hint : "default");
}

com.netflix.loadbalancer.ZoneAwareLoadBalancer#chooseServer 选择对应的服务器

@Override
    public Server chooseServer(Object key) {
    //特别重要:基本都会走这个方法,寻找父类的选择服务的方法
        if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
            logger.debug("Zone aware logic disabled or there is only one zone");
            return super.chooseServer(key);
        }
       
    }

com.netflix.loadbalancer.BaseLoadBalancer#chooseServer
选择对应的服务器的真正算法

    public Server chooseServer(Object key) {
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try {
            //特别重要:通过负载均衡算法来选择服务
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }
@Override
	public <T> T execute(String serviceId, ServiceInstance serviceInstance,
			LoadBalancerRequest<T> request) throws IOException {
		Server server = null;
		if (serviceInstance instanceof RibbonServer) {
			server = ((RibbonServer) serviceInstance).getServer();
		}
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}

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

		try {
		//特别重要:发起http请求
			T returnVal = request.apply(serviceInstance);
			statsRecorder.recordStats(returnVal);
			return returnVal;
		}

		return null;
	}

3.源码总结:

  1. RestTemPlate Spring自带的远程调用客户端
  2. @LoadBalanced 告知Spring使用负载均衡算法
  3. RestTemplateCustomizer RestTemPlate的定制器
  4. LoadBalancerInterceptor 负载均衡拦截器
  5. LoadBalancerClient 负载均衡客户端,实现类:RibbonLoadBalancerClient
  6. ILoadBalancer负载均衡器实现类:ZoneAwareLoadBalancer
  7. 负载均衡算法IRule 实现类:ZoneAvoidanceRule