Loading

Ribbon

Ribbon是SpringCloud中提供负载均衡策略的组件。

负载均衡中的角色

LoadBalancerInterceptor

对带有@LoadBalanceRestTemplate的http请求进行拦截。

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

	private LoadBalancerClient loadBalancer;

	private LoadBalancerRequestFactory requestFactory;

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

}

它的工作内容大概如下:

  1. 拦截请求,通过getHost拿到请求的服务名(还不是实际的IP地址+端口,只是服务名)
  2. 调用LoadBalancerClient执行对应的请求

LoadBalancerClient

代表一个具有负载均衡功能的客户端,继承了ServiceInstanceChooser,所以具有在多个服务实例中选择一个的能力。

上面的所有内容都是SpringCloud提供的通用API,下面的组件多是Ribbon中提供的实现组件

如果使用Ribbon负载均衡器,那么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);
}
  1. 获取一个LoadBalancer实例
  2. 通过LoadBalancer实例,拿到实际要调用的服务器
  3. 实际执行对服务器的调用

ILoadBalancer

代表软件负载均衡器的一个接口,它需要一组进行负载均衡的服务器,具有将某个服务器标记为下线的方法,具有选择一个服务器的功能。

通过打断点,发现实际上是DynamicServerListLoadBalancer这个实现类在工作,它是一种支持服务器列表在运行时动态改变的负载均衡器,它继承自BaseLoadBalancerBaseLoadBalancerchooseServer方法是这样实现的:

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;
        }
    }
}
  1. 计数,提供服务的总数
  2. 调用rule进行实际的选择

可见,这个LoadBalancer中将选择服务器的职能又委托给一种规则对象了,因为负载均衡算法不一样嘛,一个负载均衡器理应支持多种负载均衡算法。

IRule

IRule就是实际的负载均衡算法的接口了,它的choose方法用于使用它代表的负载均衡策略返回一个实际承受负载的服务器。该接口有如下实现类(不全):

img

可以在其中看到一些熟悉的名字,比如RoundRobin是轮询算法,Random是随机算法。

它的实现类AbstractLoadBalancerRule中又有如下继承者:

img

其中有最佳可访问的策略,响应时间权重的策略等等,默认工作的是RoundRobinRule,是一种轮询算法。常用的还有ZoneAvoidanceRule,是一中考虑服务器区域和可访问性的轮询算法。

总结

img

切换负载均衡算法

定义IRule Bean

在配置文件中定义IRule类型的Bean即可

@Bean
public IRule rule() {
    return new RandomRule();
}

配置文件

user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

饥饿加载

Ribbon的RibbonLoadBalancerClient默认是懒加载的,即启动时不加载某个服务的具体服务器,只有在第一次访问时才加载,所以第一次访问会较慢。

如果想取消这种默认行为,可以打开饥饿加载,即启动时就加载对应服务的服务器列表:

ribbon:
  eager-load:
    enabled: true
    clients: user-service
posted @ 2022-08-05 16:30  yudoge  阅读(143)  评论(0编辑  收藏  举报