RPC(Remote Procedure Call,远程过程调用)框架是分布式服务的基石,实现RPC框架需要考虑方方面面。其对业务隐藏了底层通信过程(TCP/UDP、打包/解包、序列化/反序列化),使上层专注于功能实现;框架层面,提供各类可选架构(多进程/多线程/协程);应对设备故障(高负载/死机)、网络故障(拥塞/网络分化),提供相应容灾措施。
RPC框架中Client调用Server,请求路由到哪台Server有不同的策略和实现方式。这里路由策略可分为三种,我们分别把它们称为Set、一致性哈希、SetModel,下面我们讨论这三种路由方式。
Set
Set即分段路由,根据请求来源的标志位(如用户ID),将请求落到对应Set的Server。各Set配置一台备机进行容灾,Set一般配置格式如下:
[Server0] IP=1.1.1.1 Port=11000 Sect_Begin=0 Sect_End=99 [BakServer0] IP=1.1.1.2 Port=11000 Sect_Begin=0 Sect_End=99
以上配置表示,0~99段的请求将落到1.1.1.1/11000,如果主机访问失败,则请求1.1.1.2/11000。
采用Set路由方式有一些弊端,作为冷备的容灾,有一半设备处于空闲状态,因用户活跃度不同,按用户ID路由请求,会导致Server请求不均,另因配置中带有分段信息,配置不易于修改,从而导致扩容/缩容的不便。
一致性哈希
一致性哈希(consistent hash)的具体实现可见《memcached客户端一致性哈希算法实现——libketama》(需 翻 墙),一致性哈希适合作为逻辑模块间的路由策略,配置格式如下:
[Server0] IP=1.1.1.1 Port=11000 Scale=1000 [Server1] IP=1.1.1.2 Port=11000 Scale=2000
Scale配置项代表权重,以上配置表示请求落到1.1.1.2这台机的概率比落到1.1.1.1大一倍。
相比Set路由方式,一致性哈希路由更方便于扩容/缩容,并且理论上可以做到请求平摊。但一致性哈希路由存在另一方面的隐患,由于没有分段隔离,少量用户带来的问题可扩散到整个后端,另动态计算请求落到哪台Server的算法需合理设计,避免在这一步消耗太多计算资源。
SetModel
SetModel路由方式是Set、一致性哈希两者的结合,在SetModel下,请求先分段落到一组Server,再根据一致性哈希在这一组Server中选取机器。SetModel配置格式如下:
[Server0] SVRCount = 3 SVR0=1.1.1.1 SVR1=1.1.1.2 SVR2=1.1.1.3 SVR_Port=11000 Sect_Begin=0 Sect_End=49 [Server1] SVRCount = 3 SVR0=1.1.1.4 SVR1=1.1.1.5 SVR2=1.1.1.6 SVR_Port=11000 Sect_Begin=50 Sect_End=99
假设用户ID为60,由以上配置请求将落到Server1这一组Server,再依据一致性哈希,在1.1.1.4、1.1.1.5、1.1.1.6这三台Server中挑选一台用于处理请求。
SetModel相比一致性哈希,避免了个别用户带来的影响扩散,但仅使用用户标志作为分Set标准,同样存在流量不均问题。在选路之前,我们可以对用户ID取一次random,再根据random值选Set,这样可解决流量不均问题。
长连 VS 短连
最后聊聊RPC框架中长短连的使用问题,长连、短连定义如下:
长连:Client维持与Server的TCP Socket连接,每次请求使用同样的连接通道
短连:Client每次请求Server即发起一次连接,当次请求完成后关闭连接
我们可以从资源使用的角度,分析使用长连还是短连,长连下Client/Server长期占用内存(tcp_mem)用于连接保持,短连下连接建立的过程会带来CPU消耗(如Server不断Accept),对CPU消耗型服务,在内存能满足的情况下,应尽量使用长连。
小结
本文讨论了RPC框架中三种路由方式,分别是Set、一致性哈希、SetModel,Set按分段提供冷备,一致性哈希保证请求均匀,SetModel是Set和一致性哈希两者的结合,最后探讨RPC框架中长连和短连的应用场景。
RPC框架的实现需要考虑方方面面,路由访问方式是其中一个点,下一节将讨论如何在RPC框架中实现容灾,解决设备故障、网络分化等问题。