负载均衡分类
硬件负载均衡
F5 就是常见的硬件负载均衡产品。
优点:性能稳定,具备很多软件负载均衡不具备的功能,如应用交换,会话交换、状态监控等。
缺点:设备价格昂贵、配置冗余,没有软件负载均衡灵活,不能满足定制化需求。
软件负载均衡
Nginx:性能好,可以负载超过 1W。工作在网络的7层之上,可以针对http应用做一些分流的策略。Nginx也可作为静态网页和图片服务器。Nginx仅能支持http、https和Email协议。
LVS(Linux Virtual Server):是一个虚拟服务器集群系统,采用 IP 地址均衡技术和内容请求分发技术实现负载均衡。接近硬件设备的网络吞吐和连接负载能力。抗负载能力强、是工作在网络4层之上仅作分发之用。自身有完整的双机热备方案,如LVS Keepalived。软件本身不支持正则表达式处理,不能做动静分离。
服务端负载均衡
Nginx 和 F5 都可以划分到服务端的负载均衡里面,后端的服务器地址列表是存储在后端服务器中或者存在专门的 Nginx 服务器或 F5 上;服务器的地址列表的来源是通过注册中心或者手动配置的方式来的;
客户端负载均衡
Ribbon 属于客户端负载均衡器,客户端自己维护一份服务器的地址列表。这个维护的工作就是由 Ribbon 来干的;Ribbon 会从 Eureka Server 读取服务信息列表,存储在 Ribbon 中,如果服务器宕机了,Ribbon 会从列表剔除宕机的服务器信息;Ribbon 有多种负载均衡算法,可以自行设定规则从而请求到指定的服务器;
Ribbon 核心组件
负载均衡器 LoadBalancer
用于管理负载均衡的组件。初始化的时候通过加载 YMAL 配置文件创建出来的。
服务列表 ServerList
ServerList 主要用来获取所有服务的地址信息,并存到本地;根据获取服务信息的方式不同,又分为静态存储和动态存储:
静态存储:从配置文件中获取服务节点列表并存储到本地。
动态存储:从注册中心获取服务节点列表并存储到本地
服务列表过滤 ServerListFilter
将获取到的服务列表按照过滤规则过滤。
- 通过 Eureka 的分区规则对服务实例进行过滤。
- 比较服务实例的通信失败数和并发连接数来剔除不够健康的实例。
- 根据所属区域过滤出同区域的服务实例。
服务列表更新 ServerListUpdater
服务列表更新就是 Ribbon 会从注册中心获取最新的注册表信息。是由这个接口 ServerListUpdater 定义的更新操作。而它有两个实现类,也就是有两种更新方式:
- 通过定时任务进行更新。由这个实现类 PollingServerListUpdater 做到的。
- 利用 Eureka 的事件监听器来更新。由这个实现类EurekaNotificationServerListUpdater做到的。
心跳检测 Ping
IPing 接口类用来检测哪些服务可用。如果不可用了,就剔除这些服务。
实现类主要有这几个:PingUrl、PingConstant、NoOpPing、DummyPing、NIWSDiscoveryPing。心跳检测策略对象 IPingStrategy,默认实现是轮询检测。
负载均衡策略 Rule
RoundRobinRule:线性轮询均衡;
RandomRule:随机负载均衡;
AvailabilityFilteringRule:可用服务过滤负载均衡,会先过滤掉由于多次访问故障而处于断路器状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问;
WeightedResponseTimeRule:加权响应时间负载均衡,根据平均响应时间计算所有服务的权重,响应时间越快的服务权重越大被选中的概率越大。刚启动时如果统计信息不足,则使用RoundRobinRule(轮询)策略,等统计信息足够,会切换到WeightedResponseTimeRule;
RetryRule:重试负载均衡,先按照RoundRobinRule(轮询)策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务;
BestAvailableRule:高可用均衡,会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;
ZoneAvoidanceRule:区域感知负载均衡,复合判断Server所在区域的性能和Server的可用性选择服务器;
自定义算法:
- 在主启动类加入@RibbonClient(name = “所要使用当前算法的微服务名称”,configuration = MySelfRule.class)代表使用自定义的java文件
- 在其他的包下建立算法类,需要符合IRule类的规则,需要extends AbstractLoadBalancerRule
- 复写Irule 接口的choose方法,将自己的算法写进去
实现原理
- Ribbon 拦截所有标注@loadBalance注解的 RestTemplate,RestTemplate 是用来发送 HTTP 请求的;
- 将 Ribbon 默认的拦截器 LoadBalancerInterceptor 添加到 RestTemplate 的执行逻辑中,当 RestTemplate 每次发送 HTTP 请求时,都会被 Ribbon 拦截;
- 拦截后,Ribbon 会创建一个 ILoadBalancer 实例;
- ILoadBalancer 实例会使用 RibbonClientConfiguration 完成自动配置。就会配置好 IRule,IPing,ServerList;
- Ribbon 会从服务列表中选择一个服务,将请求转发给这个服务;
Ribbon 心跳检测
Ribbon 不是通过每个服务向 Ribbon 发送心跳或者 Ribbon 给每个服务发送心跳来检测服务是否存活的,Ribbon 心跳检测原理:对自己本地缓存的 Server List 进行遍历,看下每个服务的状态是不是 UP 的。具体的代码就是 isAlive 方法。核心代码:isAlive = status.equals(InstanceStatus.UP);默认每隔 30s 执行以下 PingTask 调度任务,对每个服务执行 isAlive 方法,判断下状态;