翻译自:https://grpc.io/blog/grpc-load-balancing/
这是gRPC负载均衡的第一篇,后续会给出基于golang XDS服务发现的例子,了解golang XDS的工作原理。
本文描述了在部署gRPC时可能会采用的几种负载均衡场景。
大规模gRPC部署下,通常会有大量相同的后端实例以及大量客户端。由于每个服务的容量是有限的,因此会使用负载均衡在可用的服务器之间均衡来自客户端的请求。
目录
为什么使用gRPC
gRPC是一个先进的RPC协议,它是基于HTTP/2实现的。HTTP/2是一个7层协议,运行在TCP协议之上。相比传统的HTTP/REST/JSON机制,gRPC有很多优点,如:
- 它使用了二进制协议(HTTP/2)
- 在一个连接(HTTP/2)上复用多个请求
- 头部压缩(HTTP/2)
- 强类型服务和消息定义(Protobuf)
- 为多种语言实现了常用的客户端/服务器库
此外,gRPC无缝集成了如服务发现,命名解析,负载均衡,追踪和监控等生态组件。
负载均衡选项
代理负载均衡还是客户端侧负载均衡?
注:某些文章中会把代理负载均衡称为服务端侧负载均衡。
使用代理负载均衡还是客户端测负载均衡是一个主要的架构上的抉择。使用代理负载均衡时,客户端会像负载均衡(LB)代理发起RPCs,LB会将RPC请求分发到实现了该调用的可用的后端服务器上。LB会持续跟踪每个后端,并实现公平分配负载的算法。客户端本身并不知道后端服务的信息。客户端可能是不可信的。该架构通常用于面向用户的服务,开放网络下的客户端可以连接到数据中心的服务器上,如下图所示,这种场景下,客户端会像LB发生请求(#1),LB将请求分发给某个后端(#2),最后后端将结果返回给LB(#3)。
当使用客户端侧的负载均衡时,客户端会知道多个后端服务器的情况,然后为每个RPC从中选择一个处理服务器。客户端会从后端服务器接收RPC结果,且客户端会实现负载均衡算法。在更简单的配置中,可以不考虑服务器负载,客户端仅需要在可用的服务器之间进行轮询即可。如下图,客户端会向指定的服务器发送请求(#1),后端会相应负载信息(#2),客户端通常会在相同的连接上执行RPC。客户端负责更新内部状态。
下表展示了每种模型的优劣势:
Proxy | Client Side | |
优势 | 简化客户端配置 客户端侧无需了解后端信息 可以配合不可信的客户端 |
由于消除了多余的条数,提升了性能 |
劣势 | LB位于数据路径上 较高的延迟 LB的吞吐量可能会限制可扩展性 |
复杂的客户端 客户端需要持续跟踪服务端的负载和健康情况 客户端需要实现负载均衡 每个语言的实现和维护负担 需要可信的客户端,或信任边界需要由备用的LB进行处理 |
代理负载均衡选项
代理负载均衡可以工作在L3/L4或L7。在传输层的负载均衡,服务端会终止TCP连接,然后打开到选择的后端的另外一个连接。应用数据(HTTP/2个gRPC帧)会在客户端连接和后端连接之间进行拷贝。相比L7 LB,L3/L4 LB仅会进行很少的处理,且消耗的资源也更少。
在使用L7负载均衡时,LB会终结连接并解析HTTP/2协议。LB会检查每个请求并根据请求内容将其分配给一个后端。例如,带session cookie的HTTP首部可以关联一个特定的后端,因此该session的所有请求都会被该后端处理。一旦LB选择了一个合适的后端,它会跟这个后端创建一条新的HTTP/2连接,然后转发接收到的客户端到该后端的HTTP/2流。使用HTTP/2,LB可以将一个客户端的流分配给多个后端。
L3/L4 vs L7
使用场景 | 建议 |
RPC的负载在连接之间变化很大 | 使用应用层的LB |
存储或计算亲和性比较重要 | 使用应用层LB,并使用cookie类似的功能来路由请求到正确的后端 |
减小代理的资源利用率比使用其特性更重要 | 使用L3/L4 LB |
注重延迟 | 使用L3/L4 LB |
客户端侧的LB选项
胖客户端
胖客户端方式意味着在客户端实现负载均衡。客户端负责持续跟踪可用的服务器,以及服务器负载,并实现选择服务器的算法。客户端通常会集成与其他基础设施通信的库,如服务发现,命名解析,配额管理等。
备用负载均衡
注:备用负载均衡也被称为外部负载均衡或单路并联负载均衡
使用备用负载均衡时,会将其实现为一个特定的LB服务器。客户端或请求备用LB,备用LB会返回最合适的服务器。在后备LB中实现了跟踪服务器状态和LB算法实现的繁重工作。注意,客户端可能会选择在LB中实现的复杂算法之上实现简单算法。gRPC为该模型定义了一个协议,用于客户端和LB之间的通信,参见 doc 。
下图展示了这种方式。客户端从备用LB中获得至少一个地址(#1),客户端会使用该地址发起RPC(#2),服务器会将结果发送给LB(#3),备用LB会与其他基础设施通信,如命名解析,服务发现等(#4)。
建议和最佳实现
基于特定部署和限制,建议如下:
配置 | 建议 |
客户端和服务器之间流量很高 客户端可信 |
使用胖客户端负载均衡 客户端侧使用ZooKeeper/Etcd/Consul/Eureka,ZooKeeper example。 |
传统配置--很多客户端连接到位于代理之后的服务 服务器和客户端之间需要配置信任边界 |
代理负载均衡 L3/L4 LB,使用GCLB L3/L4 LB,使用haproxy - config file Nginx 如果需要会话粘性,可以使用Envoy L7 LB作为代理 |
微服务,数据中心有N个客户端,N个服务器 很高的性能要求(低延迟,大流量) 客户端可能是不可信的 |
备用负载均衡 客户端侧LB,使用 gRPC-LB protocol。 |
现有的服务网格,例如使用Linkerd或Istio进行的设置 | Service Mesh 使用内置的LB,如 Istio, 或Envoy. |