如果已经明确知道服务端支持HTTP/2,则可免去通过HTTP/1.1 101协议切换方式进行升级。TCP连接建立之后即可发送序言,否则只能在接收到服务端101响应之后发送序言
针对一个连接,服务端第一个要发送的帧必须是SETTINGS帧,连接序言所包含的SETTINGS帧可以为空
客户端可以在发送完序言之后发送应用帧数据,不用等待来自服务器端的序言SETTINGS帧
gRPC支持三种Protocol Negotiator策略:
PlaintextNegotiator:明确服务端支持HTTP/2,采用HTTP直接连接的方式与服务端建立HTTP/2连接,省去101协议切换过程。
PlaintextUpgradeNegotiator:不清楚服务端是否支持HTTP/2,采用HTTP/1.1协商模式切换升级到HTTP/2。
TlsNegotiator:在TLS之上构建HTTP/2,协商采用ALPN扩展协议,以”h2”作为协议标识符。
下面我们以PlaintextNegotiator为例,了解下基于Netty的HTTP/2连接创建流程:
(点击放大图像)
图1-7 基于Netty的HTTP/2直连流程
1.3.6. 负载均衡策略总体上看,RPC的负载均衡策略有两大类:
服务端负载均衡(例如代理模式、外部负载均衡服务)
客户端负载均衡(内置负载均衡策略和算法,客户端实现)
外部负载均衡模式如下所示:
(点击放大图像)
图1-8 代理负载均衡模式示意图
以代理LB模式为例:RPC客户端向负载均衡代理发送请求,负载均衡代理按照指定的路由策略,将请求消息转发到后端可用的服务实例上。负载均衡代理负责维护后端可用的服务列表,如果发现某个服务不可用,则将其剔除出路由表。
代理LB模式的优点是客户端不需要实现负载均衡策略算法,也不需要维护后端的服务列表信息,不直接跟后端的服务进行通信,在做网络安全边界隔离时,非常实用。例如通过Ngix做L7层负载均衡,将互联网前端的流量安全的接入到后端服务中。
代理LB模式通常支持L4(Transport)和L7(Application)层负载均衡,两者各有优缺点,可以根据RPC的协议特点灵活选择。L4/L7层负载均衡对应场景如下:
L4层:对时延要求苛刻、资源损耗少、RPC本身采用私有TCP协议
L7层:有会话状态的连接、HTTP协议簇(例如Restful)
客户端负载均衡策略由客户端内置负载均衡能力,通过静态配置、域名解析服务(例如DNS服务)、订阅发布(例如Zookeeper服务注册中心)等方式获取RPC服务端地址列表,并将地址列表缓存到客户端内存中。每次RPC调用时,根据客户端配置的负载均衡策略由负载均衡算法从缓存的服务地址列表中选择一个服务实例,发起RPC调用。
客户端负载均衡策略工作原理示例如下:
(点击放大图像)
图1-9 客户端负载均衡策略示意图
gRPC默认采用客户端负载均衡策略,同时提供了扩展机制,使用者通过自定义实现NameResolver和LoadBalancer,即可覆盖gRPC默认的负载均衡策略,实现自定义路由策略的扩展。
gRPC提供的负载均衡策略实现类如下所示:
PickFirstBalancer:无负载均衡能力,即使有多个服务端地址可用,也只选择第一个地址。
RoundRobinLoadBalancer:“RoundRobin”负载均衡策略。
gRPC负载均衡流程如下所示:
(点击放大图像)
图1-10 gRPC客户端负载均衡流程图
流程关键技术点解读:
1.负载均衡功能模块的输入是客户端指定的hostName、需要调用的接口名和方法名等参数,输出是执行负载均衡算法后获得的NettyClientTransport。通过NettyClientTransport可以创建基于Netty HTTP/2的gRPC客户端,发起RPC调用。
2.gRPC系统默认提供的是DnsNameResolver,它通过InetAddress.getAllByName(host)获取指定host的IP地址列表(本地DNS服务)。