vlambda博客
学习文章列表

架构系列十(负载均衡组件设计实现思考)

1.简介

提到负载均衡,我们最早想到的可能是nginx,f5这样一些产品解决方案。毕竟在微服务盛行以前,业界更多的是将单体应用通过集群方式部署,在集群应用前通过f5硬负载,或者通过nginx软负载,架构如下图

像上图通过nginx负载,我们叫做服务端负载均衡,且常用实现负载均衡的算法有轮询、随机等。

那么在微服务盛行的当下,我们更加需要实现负载均衡,一个典型的微服务架构如下图

架构系列十(负载均衡组件设计实现思考)


上图架构文字描述

  • 在微服务体系架构下,需要服务注册与发现组件,比如说Eureka,Nacos

  • 所有服务,启动时向注册中心注册,比如服务提供者a、服务提供者b、服务消费者

  • 服务消费者,当需要使用其它服务提供的能力时

    • 从注册中心注册表中,获取服务提供者信息

    • 服务提供者,可能是一个多实例集群部署

  • 那么服务消费者,在拿到服务提供者信息时,该如何处理呢?

  • 需要一个负载均衡组件,比如说ribbon,它可以解决

    • 从某服务的一组实例信息中(一个服务列表)

    • 根据某种负载均衡策略,选定某个实例

    • 将该实例信息,提供给服务消费者,实现服务时间的远程调用

像这样集成在服务消费者内部的负载均衡组件,比如说ribbon,我们称为客户端负载均衡。

通过上述了解负载均衡应用案例,那么假如让我们来设计实现这样一个负载均衡的组件,需要考虑哪些因素呢?

这是本篇文章的重点,下面我们一起来看一看!

2.案例

2.1.需求分析、设计实现

回归本质,负载均衡这个事情,如果从需求层面去看,会是一个什么样子呢?大概是这样,从一个数据源(服务列表资源)中,通过某种规则,选择出一个服务以供使用,简化成编程模型,即多个输入,一个输出

于是,我们可以像下面这样去考虑设计实现一个负载均衡组件,它需要包含这么一些组件

  • ServerList:服务资源列表,即数据源

  • Rule:实现多个输入,到一个输出转换的规则,即负载均衡规则,或者说是算法(轮询、随机、加权)

  • Ping:确保输出的服务实例是可用的、健康的

  • ServerListFilter:服务资源列表过滤,也许我们拿到的10个服务实例中,有2个是不满足要求的,需要过滤处理掉,最终保留8个。最后再从8个中选择1个

  • ServerListUpdater:服务资源列表更新,当注册中心注册表中的服务发生更新后,需要更新负载均衡组件,缓存的服务资源列表

  • LoadBalancer:负载均衡,作为通用的解决方案,通用组件,当与其它组件整合使用时,需要有一个使用入口,该入口整合了负载均衡自身的其它组件

你看,这样一来,我们就抽象出负载均衡产品的核心组件了。事实上,它们正是ribbon的六大核心组件

2.2.ribbon各组件源码

2.2.1.ServerList

public interface ServerList<T extends Server> { // 获取服务列表 List<T> getInitialListOfServers();
// 获取更新后的服务列表 List<T> getUpdatedListOfServers();}

具体实现参考,可以参考

  • com.netflix.loadbalancer.ConfigurationBasedServerList

  • org.springframework.cloud.netflix.ribbon.StaticServerList

  • com.alibaba.cloud.nacos.ribbon.NacosServerList

2.2.2.ServerListFilter

public interface ServerListFilter<T extends Server> { // 过滤处理传入的ServerList List<T> getFilteredListOfServers(List<T> var1);}

具体实现,可以参考

  • com.netflix.loadbalancer.ZoneAffinityServerListFilter

2.2.3.ServerListUpdater

public interface ServerListUpdater { void start(ServerListUpdater.UpdateAction var1);
void stop();
String getLastUpdate();
long getDurationSinceLastUpdateMs();
int getNumberMissedCycles();
int getCoreThreads();
// 更新客户端缓存的serverList public interface UpdateAction { void doUpdate(); }}

具体实现,可以参考

  • com.netflix.loadbalancer.PollingServerListUpdater

2.2.4.IPing

public interface IPing { // 检查服务是否健康 boolean isAlive(Server var1);}

具体实现,可以参考

  • com.netflix.loadbalancer.DummyPing

2.2.5.IRule

public interface IRule { // 根据负载均衡算法,从ServerList列表中,选择出一个服务实例 Server choose(Object var1);
void setLoadBalancer(ILoadBalancer var1);
ILoadBalancer getLoadBalancer();}

具体实现,可以参考

  • com.netflix.loadbalancer.RandomRule

  • com.netflix.loadbalancer.RoundRobinRule

  • com.alibaba.cloud.nacos.ribbon.NacosRule

2.2.6.ILoadBalancer

public interface ILoadBalancer { // 添加服务列表 void addServers(List<Server> var1); // 选择某个服务实例 Server chooseServer(Object var1); // 标记服务下线 void markServerDown(Server var1);
/** @deprecated */ @Deprecated List<Server> getServerList(boolean var1); // 获取健康可达的服务列表 List<Server> getReachableServers(); // 获取所有服务列表 List<Server> getAllServers();}

具体实现,可以参考

  • com.netflix.loadbalancer.BaseLoadBalancer

  • com.netflix.loadbalancer.DynamicServerListLoadBalancer