Ribbon学习笔记

Load Balance负载均衡是用于解决一台机器(一个进程)无法解决所有请求而产生的一种算法。像nginx可以使用负载均衡分配流量,ribbon为客户端提供负载均衡,dubbo服务调用里的负载均衡等等,很多地方都使用到了负载均衡。

使用负载均衡带来的好处很明显(系统高可用、网络压力缓解、处理能力扩容):

  1. 当集群里的1台或者多台服务器down的时候,剩余的没有down的服务器可以保证服务的继续使用
  2. 使用了更多的机器保证了机器的良性使用,不会由于某一高峰时刻导致系统cpu急剧上升

负载均衡有好几种实现策略,常见的有:

  1. 随机 (Random)
  2. 轮询 (RoundRobin)
  3. 一致性哈希 (ConsistentHash)
  4. 哈希 (Hash)
  5. 加权(Weighted)(默认会启动一个每隔30秒的定时任务来为每个服务实例计算权重.)

服务发现的任务由Eureka完成,而服务消费的任务由Ribbon完成,它是一个基于Http和TCP的客户端负载均衡器,可以通过在客户端中配置的ribbonServerList服务端列表去轮询访问以达到均衡负载的作用(对于服务提供方,同一服务的实例通常会有多个来保证服务的高可用性).

Eureka服务治理体系下实现服务的消费与发现:

先启动注册中心和服务实例应用,然后创建应用主类配置@EnableDiscoveryClient注解让这个应用注册为Eureka客户端应用,来获得服务发现的能力,然后通过@LoadBalanced来开启客户端的负载均衡能力.

@Bean(name = "balancedRestTemplate")
    @LoadBalanced
    RestTemplate balancedRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setMessageConverters(fastJsonHttpMessageConverters.getConverters());
        return restTemplate;
    }

然后根据书所说,我们可以点进RibbonLoadBalancerClient源码当中查看负载均衡的操作, 和传统的负载均衡思想是没有区别的.

// choose获取实例
@Override
	public ServiceInstance choose(String serviceId) {
		Server server = getServer(serviceId);
		if (server == null) {
			return null;
		}
		return new RibbonServer(serviceId, server, isSecure(server, serviceId),
				serverIntrospector(serviceId).getMetadata(server));
	}
// 只要看到execute方法中调用了get方法, get方法会调用choose方法, 所以就很清楚了
@Override
	public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
		Server server = getServer(loadBalancer);
		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);
	}

	@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 {
			T returnVal = request.apply(serviceInstance);
			statsRecorder.recordStats(returnVal);
			return returnVal;
		}
		// catch IOException and rethrow so RestTemplate behaves correctly
		catch (IOException ex) {
			statsRecorder.recordStats(ex);
			throw ex;
		}
		catch (Exception ex) {
			statsRecorder.recordStats(ex);
			ReflectionUtils.rethrowRuntimeException(ex);
		}
		return null;
	}

再看LoadBalancerAutoConfiguration这个类

// ConditionalOnClass 表示RestTempplate类必须存在当前工程的环境中,ConditionalOnBean表示Spring的Bean工程当中必须有LoadBalancerClient的实现Bean.

// 在这个自动化配置类当中,会创建一个拦截器LoadBalancerInterceptor的Bean,用于实现对用户请求的拦截,然后实现客户端负载均衡.

// 创建了一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadBalancerInterceptor拦截器.

/* 维护了一个被@LoadBalanced注解修饰的RestTemplate对象列表,并在这里进行初始化, 通过调用RestTemplateCustomizer的实例来给需要客户端负载均衡的RestTemplate增加LoadBalancerInterceptor拦截器.
*/

/* 当一个被@LoadBalanced注解修饰的RestTemplate对象向外发起HTTP请求时,LoadBalancerInterceptor的intercept方法会拦截它,然后调用execute方法根据服务名来选择实例来发起实际请求.
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
}

参考链接:https://blog.csdn.net/wudiyong22/article/details/80829808 Ribbon的负载均衡策略及原理

猜你喜欢

转载自blog.csdn.net/qq_38835878/article/details/89532419