Spring Cloud Feign的loadbalancerkey扩展

Posted by CaiJiahe on January 5, 2018

0x01 netflix-loadbalancer

在微服务的水平扩展和微服务的状态性上的权衡,考虑微服务有状态,在客户端做静态hash。但是随之而来的问题就是ribbon balancer并不支持这种静态hash的策略选择。代码如下:

	// spring-cloud-netflix-core org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient
	@Override
	public Response execute(Request request, Request.Options options) throws IOException {
		try {
			URI asUri = URI.create(request.url());
			String clientName = asUri.getHost();
			URI uriWithoutHost = cleanUrl(request.url(), clientName);
			FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
					this.delegate, request, uriWithoutHost);

			IClientConfig requestConfig = getClientConfig(options, clientName);
			return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
					requestConfig).toResponse();
		}
		catch (ClientException e) {
			IOException io = findIOException(e);
			if (io != null) {
				throw io;
			}
			throw new RuntimeException(e);
		}
	}
	
	// ribbon-loadbalancer com.netflix.client.AbstractLoadBalancerAwareClient
	public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
        RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, requestConfig);
        LoadBalancerCommand<T> command = LoadBalancerCommand.<T>builder()
                .withLoadBalancerContext(this)
                .withRetryHandler(handler)
                .withLoadBalancerURI(request.getUri())
                .build();
		
		...
	}
	
	public class LoadBalancerCommand<T> {
		
		public static class Builder<T> {
			
			private Object              loadBalancerKey;
			...
		}
	}
	

从上面可以看到ribbon-loadbalancer包并没有设置loadBalancerKey。

netflix/ribbon add loadBalancerKey when building a LoadBalancerCommand #309
上面的merge里提供了customizeLoadBalancerCommandBuilder这个方法,可以使用子类重写这个方法,来手动的设置Loadbalancerkey。
netflix-loadbalancer-2.2.4.jar及以上版本。

0x02 spring-cloud-netflix-core

虽然设置loadbalancerkey的问题解决了,但是如何从feign的声明式客户端把自定义的key值传入呢?
spring-cloud/spring-cloud-netflix public FeignLoadBalancer.RibbonRequest and FeignLoadBalancer.RibbonRe… #2536
上面的链接里把RibbonRequest修改为可重写的,所以我们可以重写这个request,在子类中设置loadbalancerkey,这样就可以将自定义的key值传入到ILoadBalancer的chooseServer中,这样就可以使用ribbon实现客户端自定义hash了。
这个代码目前还没在release的版本中,静静等待。