[Learn to enjoy Netflix] sixty, Ribbon has the ability to load balance client: AbstractLoadBalancerAwareClient

When you want to find a mistake in your code, it is difficult; when you think your code is not an error, which is even harder.

-> return column List <-
download Address: https://github.com/f641385712/netflix-learning

Foreword

Ribbon is not just load balancing, load balancing is just one of its core, the most famous of the module only. In the chat ribbon-corewhen we know that it has a core API is IClientthat indicates sends a request to get a response, does not specify the transmission method, protocol and so on.

Because Ribbon core function is to load balance, and therefore this article we will learn it has a load-balancing capabilities of the client: AbstractLoadBalancerAwareClient, it is in the jar: ribbon-loadbalancer.


text

AbstractLoadBalancerAwareClient

Because we are less likely to use the Ribbon when other, but only as load balancing, so you can be understood as simple and crude: AbstractLoadBalancerAwareClientthe top-level parent of all the client implementation , but in fact it is.

It should be noted that not only the abstract class implements an interface IClient, and also inherited from LoadBalancerContext, so it is not just own a Client, load balancing also has a context.

The abstract class has no member properties, provides a number of ways:


Initialization method

It provides two constructors for initialization.

public abstract class AbstractLoadBalancerAwareClient<S extends ClientRequest, T extends IResponse> extends LoadBalancerContext implements IClient<S, T>, IClientConfigAware {

    public AbstractLoadBalancerAwareClient(ILoadBalancer lb) {
        super(lb);
    }
    public AbstractLoadBalancerAwareClient(ILoadBalancer lb, IClientConfig clientConfig) {
        super(lb, clientConfig);        
    }

}

As a load-balancing and related Client, load balancer ILoadBalanceris essential for myself.


buildLoadBalancerCommand () to build load-balancing command

Ribbon All requests are executed based on the command mode to be executed, and therefore require packaged as a LoadBalancerCommandcommand:

AbstractLoadBalancerAwareClient:

	// 抽象方法:提供一个RequestSpecificRetryHandler重试处理器
	// 因为重试方案父类定不了:有些是超时重试,有些是异常重试,因此交给子类去决定为好
	// 但请保证是RequestSpecificRetryHandler的子类:因为它已经帮你实现了写基本逻辑
	// 一般使用包装器模式,给RequestSpecificRetryHandler.fallback赋值了就好
	public abstract RequestSpecificRetryHandler getRequestSpecificRetryHandler(S request, IClientConfig requestConfig);
	// 毕竟LoadBalancerCommand的属性众多,默认只给其设置必要的属性,其它的交给调用者去个性化吧
	// 比如常用的:增加监听器来监听必要的执行过程
	protected void customizeLoadBalancerCommandBuilder(S request, IClientConfig config, LoadBalancerCommand.Builder<T> builder) {
		// 空实现,交给子类去定制
	}

	// request请求对象,提供URI(注意不是URL,因为不一定是网络请求)
    protected LoadBalancerCommand<T> buildLoadBalancerCommand(S request, IClientConfig config) {
    	// 得到重试处理器:因为重试处理器对LoadBalancerCommand的行为特别重要
		RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, config);
		LoadBalancerCommand.Builder<T> builder = LoadBalancerCommand.<T>builder()
				.withLoadBalancerContext(this)
				.withRetryHandler(handler)
				.withLoadBalancerURI(request.getUri());
		customizeLoadBalancerCommandBuilder(request, config, builder);
		return builder.build();
	}

It leaves an abstract method and a method to hook AbstractLoadBalancerAwareClientto complete the customization ~


executeWithLoadBalancer () with the implementation of load balancing capabilities

It is not an interface method: because the interface method does not have load balancing capabilities. But it is much more important way: packaging the execute()interface method, on the LoadBalancerCommandinside so you have to perform load balancing capability.

AbstractLoadBalancerAwareClient:

	// 注意:接口方法只有execute,这是在外层套了一个负载均衡器,均由负载均衡的能力
    public T executeWithLoadBalancer(S request) throws ClientException {
        return executeWithLoadBalancer(request, null);
    }

    public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
    	// 构建一个执行命令:command
    	LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);


		// 提交目标操作/目标请求  -> 执行目标方法
    	return command.submit(server -> {
    		// 根据LB选中的Server,构建出一个最终的URI
    		// 因为你的URI可能没有host、port等是不完整的
    		URI finalUri = reconstructURIWithServer(server, request.getUri());
    		// 给request重新制定一个新的URI
    		S requestForServer = (S) request.replaceUri(finalUri);
    		
    		// execute执行目标方法:一般是发送http请求,当然这不是一定的~
    		return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
    	})
    	// 阻塞的,顺序执行 使用RxJava是为了编程方便、优美
		.toBlocking()
		.single();
    }
}

Description: In order to clear code structure, built a lot of try ... catch are omitted

The core essence of the method is: use LoadBalancerCommandpackaging executetarget method, so that it has a load-balancing capabilities. Therefore, in practical application: Do not directly call the executemethod, but using more upper, more powerful executeWithLoadBalancer()methods.


If only in ribbon-loadbalancerwithin the jar, IClientthe system has one and only in this sub-category AbstractLoadBalancerAwareClient, and it is an abstract class. Since the load balancer is not limited to that particular protocol, such as http, tcp, udp, etc. are load balancing can be done so in this jar does not have any particular Client implementation class .

But in Spring Cloud environment, a thriving:

Here Insert Picture Description
Here Insert Picture Description
It will not go Spring Cloud in its implementation, but put it in the relevant sections and in Spring Cloud integration.


ClientFactory

Since the Client is so important, in order to quickly and easily get a Client instance, Ribbon provides ClientFactorythis factory class. This class is used to quickly create a IClientclient ILoadBalancer, IClientConfigsuch as factories. It also maintains the internal and global Map, get cache to improve efficiency.

public class ClientFactory {

	// key是ClientName  value是Client实例
	private static Map<String, IClient<?,?>> simpleClientMap = new ConcurrentHashMap<>();
	// key是Lb的名称  value是LB实例
	private static Map<String, ILoadBalancer> namedLBMap = new ConcurrentHashMap<>();
	// key是ClientName  value是该client对应的配置(含默认配置)
	private static ConcurrentHashMap<String, IClientConfig> namedConfig = new ConcurrentHashMap<>();

	// ==========工具方法们=========
	
	// 反射创建一个实例,并且调用其initWithNiwsConfig()方法把config传递给它
	public static Object instantiateInstanceWithClientConfig(String className, IClientConfig clientConfig) {
		...
		IClientConfigAware obj = (IClientConfigAware) clazz.newInstance();
		obj.initWithNiwsConfig(clientConfig);
		return obj;
	}

	// 反射创建一个clientConfigClass类型的配置。IClientConfig接口的自带实现仅有DefaultClientConfigImpl
	// 注意config.loadProperties(name)方法会被调用哦(配置会被加载进来)
	// 最后放进缓存(缓存里就返回缓存里的)
	public static IClientConfig getNamedConfig(String name, Class<? extends IClientConfig> clientConfigClass) {
        IClientConfig config = namedConfig.get(name);
        if (config != null) {
            return config;
        } 
        config = (IClientConfig) clientConfigClass.newInstance();
        config.loadProperties(name);
        ...
        return config;
	}
    public static IClientConfig getNamedConfig(String name) {
        return 	getNamedConfig(name, DefaultClientConfigImpl.class);
    }

	... // 创建`ILoadBalancer`实例的方法几乎一模一样,略

	// 提供名称和客户端配置的实用程序方法来创建客户端和负载均衡器(如果在客户端配置中启用)
	// InitializeNFLoadBalancer默认配置值是true,开启负载均衡器的
	public static synchronized IClient<?, ?> registerClientFromProperties(String restClientName, IClientConfig clientConfig) throws ClientException {
    	IClient<?, ?> client = null;
    	ILoadBalancer loadBalancer = null;
    	// 如果同名的Client已经创建过了,在调用此方法就抛错,而并非把缓存里的返回给你
    	if (simpleClientMap.get(restClientName) != null) {
    		throw new ClientException(ClientException.ErrorType.GENERAL, "A Rest Client with this name is already registered. Please use a different name");
    	}
    	... // 反射创建Client、LB的实例
		simpleClientMap.put(restClientName, client);
		return client;
	}

	// 它木有传入配置:所以全部使用外部化配置
    public static synchronized IClient getNamedClient(String name) {
        return getNamedClient(name, DefaultClientConfigImpl.class);
    }
    public static synchronized IClient getNamedClient(String name, Class<? extends IClientConfig> configClass) {
    	if (simpleClientMap.get(name) != null) {
    	    return simpleClientMap.get(name);
    	}
    	return createNamedClient(name, configClass);
    }
}

Which ClientFactory.instantiateInstanceWithClientConfig()method is the most versatile: it can help you instantiate instances of any instance, including the five core components. The advantage is that you automatically After initialization call initWithNiwsConfig()method complete property assignment -


to sum up

About Ribbon with load balancing capabilities of the client: AbstractLoadBalancerAwareClient it first introduced to this, though mentioned in this article are wood and concrete implementation class code examples are given, but once you understand it (in fact, the core is LoadBalancerCommand) you would think the other is a pediatrician, this will continue to be described later when explaining integration.

So far, about Ribbon by far the most core part (core and contains loadbalancer) will introduce all over, although this project has now been stopped more, but stop with more non-stop , is still the mainstream (or even the only) client load balancing device. It can be used not only to learn in the Spring Cloud system with ease, such as the framework for understanding dubbo load balancing mechanism are easy, the other as far as I understand in-depth understanding Ribbon, and people have the ability to use it to achieve multi-zone deployment is not much, so If you master your promotion and pay rise is not that the weight of it ~

Of course, this is not the whole series Ribbon, behind but also about the integration of combat in Spring Cloud. With strong theoretical support to do, to explain the very real fast.
Dividing line

statement

The original is not easy, not easy to code word, thank you for your thumbs, collection, attention. 把本文分享到你的朋友圈是被允许的,但拒绝抄袭. You can also scan code [left / or add wx: fsx641385712] I invite you to join the Java Engineering, Architect Series family group learning and communication.
Past Featured

Published 362 original articles · won praise 531 · views 480 000 +

Guess you like

Origin blog.csdn.net/f641385712/article/details/104998870