gRPC - 负载均衡

一、官方文档

以下内容为官方文档的中文翻译,源文档地址为:
https://github.com/grpc/grpc/blob/master/doc/load-balancing.md

1. 背景

1.1. 每调用负载均衡

值得注意的是,gRPC内部的负载均衡是基于每次调用而不是每个连接的基础上发生的。换句话说,即使所有请求来自单个客户端,我们仍然希望它们在所有服务器之间进行负载均衡。

1.2. 负载均衡的方法

在进行任何gRPC详细说明之前,我们将探索一些常见的实现负载平衡的方法。

1.2.1. 代理模式

使用代理提供了一个可靠的、可信任的客户端,可以向负载平衡系统报告负载。代理通常需要更多的资源来操作,因为它们具有RPC请求和响应的临时副本。这个模型也增加了RPC的延迟。

在考虑像存储这样的大请求量服务时,代理模式被认为是低效的。

1.2.2. 均衡感知客户端

这个厚重客户端将更多的负载均衡逻辑放在客户端中。例如,客户端可以包含许多用于从列表中选择服务器的负载均衡策略(Round Robin, Random等)。在这个模型中,服务器列表将可以被静态地配置在客户端,或者由名称解析系统提供,或者依赖于一个外部的负载均衡器,等等。无论如何,客户端负责从列表中选择首选服务器。

这种方法的缺点之一是用多种语言和/或客户端版本编写和维护负载平衡策略。这些策略可能相当复杂。其中一些算法还需要客户端到服务器之间的通信,因此除了为用户请求发送RPC之外,客户端还需要变得更厚,以支持额外的RPC来获取健康或加载信息。

这也会使客户端的代码变得非常复杂:新的设计隐藏了多层的负载平衡复杂性,并将其作为一个简单的服务器列表呈现给客户端。

1.2.3. 外部负载均衡服务

客户端负载平衡代码保持简单和可移植性,实现用于服务器选择的著名算法(例如,RoundRobin)。复杂的负载均衡算法由负载均衡器提供。客户端依赖于负载均衡器来提供负载均衡配置和客户端应该向其发送请求的服务器列表。负载均衡器根据需要更新服务器列表,以平衡负载,并处理服务器不可用或健康问题。负载均衡器将作出任何必要的复杂决定,并通知客户。负载均衡器可与后端服务器通信,以收集负载和健康信息。

2. 要求

2.1. 简单的API和client

gRPC客户端负载平衡代码必须简单且可移植。客户端应该只包含用于服务器选择的简单算法(例如,RoundRobin)。对于复杂的算法,客户端应该依赖负载均衡器来提供负载平衡配置和客户端应该向其发送请求的服务器列表。均衡器将根据需要更新服务器列表,以平衡负载以及处理服务器不可用或健康问题。负载均衡器将作出任何必要的复杂决定,并通知客户。负载均衡器可与后端服务器通信,以收集负载和健康信息。

2.2. 安全

负载均衡器可能与实际服务器后端分离,负载均衡器的妥协只会导致负载平衡功能的妥协。换句话说,妥协的负载均衡器不应该使客户端信任(可能是恶意的)后端服务器,就像在没有负载平衡的类似情况下一样。

3. 架构

3.1. 概观

grpc中负载平衡的主要机制是外部负载平衡,其中外部负载均衡器为简单的客户端提供了最新的服务器列表。

gRPC客户端确实支持内置负载平衡策略的API。但是,其中只有一小部分(其中之一是实现外部负载平衡的grpclb策略),因此不鼓励用户尝试通过添加更多的方法来扩展gRPC。相反,应该在外部负载平衡器中实现新的负载平衡策略。

3.2. 工作流程

在名称解析和到服务器的连接之间,负载平衡策略适合于gRPC客户端工作流。这一切都是这样运作的:

load-balancing.png

1.在启动时,GRPC客户端发出服务器名称的名称解析请求。名称将解析为一个或多个IP地址,每个IP地址将指示它是服务器地址还是负载均衡器地址,以及一个服务配置,该配置指示要使用哪个客户端负载平衡策略(例如,循环_robin或grpclb)。

2.客户端实例化负载平衡策略。
注意:如果解析器返回的任何一个地址都是均衡器地址,那么客户端将使用grpclb策略,而不管服务配置请求的是什么负载平衡策略。否则,客户端将使用服务配置请求的负载平衡策略。如果服务配置没有请求负载平衡策略,那么客户机将默认为选择第一个可用的服务器地址的策略。

3.负载平衡策略为每个服务器地址创建一个子通道。

  • 对于除grpclb之外的所有策略,这意味着解析器返回的每个地址都有一个子通道。请注意,这些策略忽略解析器返回的任何均衡器地址。
  • 对于grpclb策略,工作流如下:
    a. 为从解析器返回的均衡地址中的某一个打开一个流,它要求服务器地址的平衡器用于客户机最初请求的服务器名称(即最初传递给名称解析器的服务器名称)。
    注意:在grpclb策略中,解析器返回的非平衡器地址被用作后备,以防在LB策略启动时无法与平衡器联系。
    b. 负载均衡器所指向的gRPC服务器可以向负载平衡器报告负载,如果负载均衡器的配置需要该信息的话。
    c. 负载平衡器将服务器列表返回给gRPC客户端的grpclb策略。然后,grpclb策略将为列表中的每个服务器创建一个子通道。
  1. 对于发送的每个RPC,负载平衡策略决定应该将RPC发送到哪个子通道(即哪个服务器)。
    在grpclb策略的情况下,客户端将按照负载均衡器返回服务器的顺序向服务器发送请求。如果服务器列表为空,则调用将被阻塞,直到接收到非空调用为止。

二、详细描述

以下内容为网络资源转述,若有侵权,请私信联系删除。原文章地址:https://segmentfault.com/a/1190000008672912

1. 集中式LB(Proxy Model)

集中式LB.png

在服务消费者和服务提供者之间有一个独立的LB,通常是专门的硬件设备如 F5,或者基于软件如 LVS,HAproxy等实现。LB上有所有服务的地址映射表,通常由运维配置注册,当服务消费方调用某个目标服务时,它向LB发起请求,由LB以某种策略,比如轮询(Round-Robin)做负载均衡后将请求转发到目标服务。LB一般具备健康检查能力,能自动摘除不健康的服务实例。 该方案主要问题:

  1. 单点问题,所有服务调用流量都经过LB,当服务数量和调用量大的时候,LB容易成为瓶颈,且一旦LB发生故障影响整个系统;
  2. 服务消费方、提供方之间增加了一级,有一定性能开销。

2. 进程内LB(Balancing-aware Client)

进程内LB.png

针对第一个方案的不足,此方案将LB的功能集成到服务消费方进程里,也被称为软负载或者客户端负载方案。服务提供方启动时,首先将服务地址注册到服务注册表,同时定期报心跳到服务注册表以表明服务的存活状态,相当于健康检查,服务消费方要访问某个服务时,它通过内置的LB组件向服务注册表查询,同时缓存并定期刷新目标服务地址列表,然后以某种负载均衡策略选择一个目标服务地址,最后向目标服务发起请求。LB和服务发现能力被分散到每一个服务消费者的进程内部,同时服务消费方和服务提供方之间是直接调用,没有额外开销,性能比较好。该方案主要问题:

  1. 开发成本,该方案将服务调用方集成到客户端的进程里头,如果有多种不同的语言栈,就要配合开发多种不同的客户端,有一定的研发和维护成本;
  2. 另外生产环境中,后续如果要对客户库进行升级,势必要求服务调用方修改代码并重新发布,升级较复杂。

3. 独立 LB 进程(External Load Balancing Service)

独立LB进程.png

该方案是针对第二种方案的不足而提出的一种折中方案,原理和第二种方案基本类似。
不同之处是将LB和服务发现功能从进程内移出来,变成主机上的一个独立进程。主机上的一个或者多个服务要访问目标服务时,他们都通过同一主机上的独立LB进程做服务发现和负载均衡。该方案也是一种分布式方案没有单点问题,一个LB进程挂了只影响该主机上的服务调用方,服务调用方和LB之间是进程内调用性能好,同时该方案还简化了服务调用方,不需要为不同语言开发客户库,LB的升级不需要服务调用方改代码。

该方案主要问题:部署较复杂,环节多,出错调试排查问题不方便。

三、负载均衡实现

根据gRPC官方提供的设计思路,基于进程内LB方案(即第2个案,阿里开源的服务框架 Dubbo 也是采用类似机制),结合分布式一致的组件(如Zookeeper、Consul、Etcd),可找到gRPC服务发现和负载均衡的可行解决方案。

实现参考:https://medium.com/@mykidong/howto-grpc-java-client-side-load-balancing-using-consul-8f729668d3f8

你可能感兴趣的:(gRPC - 负载均衡)