写点什么

Spring cloud 之 LoadBalancer 篇

作者:邱学喆
  • 2022 年 3 月 06 日
  • 本文字数:2972 字

    阅读完需:约 10 分钟

Spring cloud之LoadBalancer篇

一. 概述

在微服务架构之负载均衡启动到承上启下的作用,按照指定的分发规则将流量分发到各个节点上,从而在一定程度上提高各个服务的运行效率。

负载均衡是基于提供了服务器列表中按照指定的算法(规则)去选出一个服务节点进行分发。目前市场上的负载算法(参考 nginx 的负载算法、现有的 spring cloud 的算法,以及 LVS 的负载算法),分类归纳如下:

  • 请求报文算法,是基于请求报文内容维度进行负载策略。如用户 ID、请求 ID 等不同维度的请求报文内容;

  • IP 算法,根据服务器 IP 这个维度进行的负载策略。

  • 随机

  • 轮询

  • IP 哈希

  • 权重算法,也叫加权方式。市场上常说的灰度发布,基本上都是基于权重算法,来达到平滑过渡的发布方式。

  • 粘性连接,即第一次连接的目标 IP,后续的请求都分发到这个 IP 地址上。

  • 基于请求路径进行负载策略

  • TCP 算法,根据网络层面上的指标进行的负载策略,如连接数,响应时间,backlog 等维度。

  • 最少连接,即分发到连接数最少的服务节点上。这里有两个维度,一个是以客户端的角度,客户端连接各个服务器的连接数;另外一个是以服务端的角度,服务端提供的连接数。

  • 最小延迟时间,即服务器处理请求的最短响应时间。客户端会采集各个服务节点的响应时间,从而从中选出响应时间最短的服务节点进行分发;

  • 积压队列,当服务节点没有可用连接时,请求会暂时保存到 backlog 指定数量的集合中,待服务器处理完当前请求后,再去从积压队列中消费请求;这个在微服务中,基本是用不到的;因为在用户态中是拿不到这个指标的,只有内核态中拿到;所以这个可以不用考虑

  • OS 算法,通过采集服务器的各项指标从而进行的负载策略,如 CPU,内存,IO 等。这个目前没有开源的算法可以进行参考的,知道有这方面的策略即可。

当然里面还有组合的,如加权最少连接等。

spring cloud 的负载交互,基于注册中心交互而梳理的简单流程图如下:

二. Spring Cloud 负载

本节是基于 Spring Cloud 3.x 的源码进行解读的;基于上面的交互图再次细分一下,流程图一下:

基于 Resttemplate 发送请求的交互图,这里面涉及到了 Spring cloud commons 包中对负载相关的组件,如图所示:

基于 WebClient 发送请求的交互图,跟 Resttemplate 的交互图差不多,只是代码呈现方式不一样而已;可以查看 LoadBalancedExchangeFilterFunction 这个接口对应的实现类的过滤细节。

涉及到相关组件,将逐个讲解。

2.1 ***RequestTransformer

将 request 请求进行转换,通过这个接口,我们可以对 request 进行串改。具体细节可以通过查看其实现类。

基于 Resttemplate 使用的是 LoadBalancerRequestTransformer 接口,而 WebClient 使用的是 LoadBalancerClientRequestTransformer。

2.2 LoadBalancerClient

负载均衡客户端,该接口主要是做协调工作。

注意的是,WebClient 并没有使用该接口;

2.3 ReactiveLoadBalancer.Factory

用来创建负载均衡器的工厂类,该实现类是 LoadBalancerClientFactory,其实现原理是复用 spring 容器的形式来做的;所以,我们可以灵活的创建不同的负载均衡器,以及对不同的添加不同的定制内容。

2.3.1 LoadBalancerProperties

负载均衡器对应的相关配置信息,主要是心跳检测,以及重试机制,sticky 机制。

2.3.2 @LoadBalancerClient

该注解自定义每个目标服务对应的负载均衡器的配置信息;最终封装成 LoadBalancerClientSpecification 实例注入到 spring 容器内。

2.3.3 ReactorServiceInstanceLoadBalancer

负载均衡器。在 spring cloud common 有提供了两种实现方式,如随机、轮询等。

我们可以通过实现该接口去定制我们的负载均衡器,同时可以通过 @LoadBalancerClient 来指定不同目标服务的对应的负载策略器。

其原理是通过 spring 容器去扫描 @LoadBalancerClient 指定的配置类,将该类中相关的负载均衡器相关实例注入到该目标服务的所对应的 spring 容器。

2.4 ReactiveLoadBalancer

具体的负载均衡器,其主要的工作的筛选出目标 IP。

2.5 ServiceInstanceListSupplier

其接口主要是返回了目标 IP 列表;如果使用了注册服务发现,例如 eureka 的,则实现类 DiscoveryClientServiceInstanceListSupplier。

然而其不单单只是返回目标 IP 列表,同时也包含了额外的过滤规则以及额外的特性。

  • CachingServiceInstanceListSupplier 其缓存目标 IP 列表

  • HintBasedServiceInstanceListSupplier 可以根据 hint 提示来筛选目标 IP 列表

  • RequestBasedStickySessionServiceInstanceListSupplier 粘性

三. 实践


对 spring cloud LoadBalancer 介绍了大体的组件以及交互过程。需要实践,才可以进一步掌握的。

1. Resttemplate 负载入门

第一步:使用带有负载均衡的 resttemplate 实例

@LoadBalancedRestTemplate restemplate;
复制代码

第二步:正常调用 Resttemplate 发送请求

restemplate.post("service-id/path...",request,responseType)
复制代码

默认情况下使用的是轮询负载均衡器。

2. 进阶-定制加权负载

第一步: 往 spring 容器注入加权负载均衡器

package com.michael.b.loadbalancer;
import org.springframework.beans.factory.ObjectProvider;import org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.client.loadbalancer.DefaultResponse;import org.springframework.cloud.client.loadbalancer.Request;import org.springframework.cloud.client.loadbalancer.Response;import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;import org.springframework.stereotype.Component;import reactor.core.publisher.Mono;@Componentpublic class WeightedLoadBalancer implements ReactorServiceInstanceLoadBalancer {
final String serviceId; ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
public WeightedLoadBalancer(String serviceId, ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) { this.serviceId = serviceId; this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider; }
@Override public Mono<Response<ServiceInstance>> choose(Request request) { ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider .getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get(request)//获取目标IP列表 .next() .map(serviceInstances/*目标IP列表*/ -> {//加权算法筛选出目标IP //获取加权配置信息 //从中筛选出权重最大的IP实例 //减少当前IP的权重值 //返回当前IP实例 return new DefaultResponse(/*目标实例*/); }); }}
复制代码

第二步:正常调用 Resttemplate 发送请求

restemplate.post("service-id/path...",request,responseType)
复制代码

3. 高阶

通过 Hint 方式,以及 @LoadBalancerClient 注解去定制各个目标服务的负载均衡器等。这里就不再过多阐述。感兴趣的自行通过代码去了解其原理,并实现定制化的负载均衡器

发布于: 刚刚阅读数: 2
用户头像

邱学喆

关注

计算机原理的深度解读,源码分析。 2018.08.26 加入

在IT领域keep Learning。要知其然,也要知其所以然。原理的爱好,源码的阅读。输出我对原理以及源码解读的理解。个人的仓库:https://gitee.com/Michael_Chan

评论

发布
暂无评论
Spring cloud之LoadBalancer篇_负载均衡_邱学喆_InfoQ写作平台