¿Conoces el principio de la cinta?

que es cinta

Ribbon es un proyecto lanzado por Netflix, principalmente para proporcionar a los clientes algoritmos de equilibrio de carga de software y llamadas de servicio. El componente Ribbon proporcionará una serie de configuraciones, como tiempo de espera de conexión, reintento, etc. En pocas palabras, es enumerar todas las máquinas detrás de Load Balancer en el archivo de configuración, y luego Ribbon lo ayudará automáticamente a usar una determinada regla para conectar estas máquinas.

Principios de arquitectura

Ribbon es solo un componente de cliente de equilibrio de carga suave que se puede usar en combinación con otros clientes que requieren solicitudes. Eureka aquí es solo un ejemplo.

Ejemplo de cinta

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

@Test
public void xdclassproductInfo() {
    String id = UUID.randomUUID().toString();
    String url = "http://xdclass-shop-product/product/info?id=" + id;
    Object result = this.restTemplate.getForObject(url, HashMap.class);
    System.out.println(JsonUtil.BeanToJson(result));
}
复制代码

Como se muestra arriba, cuando Ribbon envía una solicitud, ¿cuál es el flujo de ejecución de la solicitud?

El principio de LoadBalanced

Del código anterior, podemos ver que el equilibrio de carga solicitado por RestTemplate se puede lograr a través de una anotación @LoadBalanced, entonces, ¿cuál es su principio?

Se puede ver que cuando Ribbon envía una solicitud, será interceptada por un cliente llamado ClientHttpRequestInterceptor. LoadBalancerInterceptor es la clase de implementación de ClientHttpRequestInterceptor. Su función es usar el equilibrio de carga, y la lógica del equilibrio de carga se entrega a loadBalancer.

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
		final ClientHttpRequestExecution execution) throws IOException {
	final URI originalUri = request.getURI();
	String serviceName = originalUri.getHost();
	Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
	return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
复制代码

Cabe señalar que la anotación @LoadBalanced aquí pertenece a Spring, no a Ribbon. Cuando Spring inicializa el contenedor, si detecta que el bean está anotado por LoadBalanced, Spring lo configurará como el interceptor LoadBalancerInterceptor.

Mire la definición de anotación LoadBalanced nuevamente

@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
复制代码

Puede ver que hay una variable de clase FIELD, que se puede anotar con el parámetro en la anotación. Por supuesto, esta anotación también se modifica mediante @Qualifier en el objeto bean.

Instancia del servicio de actualización dinámica

服务的实例上下线在我们微服务场景里其实是非常的常见,Ribbon也是实现了这个功能。在Ribbon的定时更新接口是ServerListUpdater。在Ribbon在注册中心获取到所有的服务实例列表之后,Ribbon这时候就需要动态的更新服务实例。另一种就是通过了事件通知的这种方式。

定时拉取

Ribbon会用定时任务线程来定时拉取更新的数据

int coresize = poolsizeProp.get();
ThreadFactory factory = (new ThreadFactoryBuilder())
.setNameFormat("PollingServerListUpdater-%d ").setDaemon(true)
.build();
serverListRefreshExecutor = new ScheduledThreadPoolExecutor(coreSize,factory);
复制代码

{service-name}.ribbon.ServerListRefreshInterval主要是更新的频率

DynamicServerListLoadBalancer.ThreadPoolSize定时更新的线程数目

@override
public synchronized void start(final UpdateAction updateAction){
    if (isActive.compareAndSet( expect: false, update: true)) {
       final Runnable wrapperRunnable = new Runnable(){
@override
public void run()i
    if (!isActive.get()){
      if (scheduledFuture != null) {
     scheduledFuture.cancel( mayInterruptlfRunning: true);
   }
    return;
  }
    try {
       updateAction.doUpdate();
       lastUpdated = System.currentTimeMillis();}catch (Exception e){
      logger.warn("Failed one update cycle",e);
 }
 };
      scheduledFuture = getRefreshExecutor().schedulewithFixedDelay(
      wrapperRunnable,
    initialDelayMs,refreshIntervalMs,TimeUnit.MILLISECONDS
  );
   }else {
     logger.info("Already active,no-op");
}
复制代码

PollingServerListUpdater它只是对线程池进行了控制,但是它的具体业务就封装在了UpdateAction了。

对服务进行心跳检测

在服务的列表当中,实例不一定一直都是可用的状态,Ribbon就会对服务来进行检测,PingerStrategy接口的检测策略,Ribbon默认就是使用串行的这种方式来进行检测的,也可以通过这个接口使用并行的检测方式。Pinger就会定时通过PingerStrategy来获取到更得多的服务实例,并且调用监听者。

//在线服务实例列表
final List<Server> newUpList = new ArrayList<Server>();
//发生状态变更的服务实例列表
final List<Server> changedServers = new ArrayList<Server>();

for (int i = 0; i < numCandidates; i++) {
    boolean isAlive = results[i];
    Server svr = allServers[i];
    boolean oldIsAlive = svr.isAlive();

    svr.setAlive(isAlive);

    if (oldIsAlive != isAlive) {
        changedServers.add(svr);
        logger.debug("LoadBalancer [{}]:  Server [{}] status changed to {}", 
            name, svr.getId(), (isAlive ? "ALIVE" : "DEAD"));
    }

    if (isAlive) {
        newUpList.add(svr);
    }
}
复制代码

负载均衡调度器

从一个ServerListFilter获取到一个微服务的实例集合之后,ILoadBalancer就需要使用某一个策略从集合里选择一个服务实例。

public interface IRule{
    //省略一些方法
    public Server choose(Object key);

}
复制代码

选择服务实例之后,ILoadBalancer在调用过程中,会记录请求的执行结果,比如请求的失败成功情况,调用耗时等,IRule接口也可以根据这些信息决定是否使用某个Server

Ribbon的负载均衡策略

1、 RoundRobinRule(轮询)

2、RandomRule(随机策略)

3、BestAvailableRule(过滤出故障服务器后,选择一个并发量最小的)

4、WeightedResponseTimeRule(针对响应时间加权轮询)

5、AvailabilityFilteringRule(可用过滤策略,先过滤出故障的或并发请求大于阈值的一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个;)

6、ZoneAvoidanceRule(从最佳区域实例集合中选择一个最优性能的服务实例)

7、RetryRule(选择一个Server,如果失败,重新选择一个Server重试)

Supongo que te gusta

Origin juejin.im/post/7085174806479372296
Recomendado
Clasificación