分布式RPC设计思想


分布式所要解决的问题就是当系统中的个别节点发生故障后整个系统依然能够稳定的对外提供服务,对于

RPC框架来说同样也是;多线程和多进程解决的都是并发的问题,无论怎样都只能算是单点的设计,要想保证

系统的高可用性,分布式的设计必不可少。下面就介绍一些RPC框架设计中关于分布式的一些思想

3ya4f0.jpg

一、客户端连接池

如果RPC的服务端部署在多个节点上时,客户端得出的是一个服务列表,有多个IP端口对,客户端的

连接池可以随机挑出任意的RPC服务节点进行连接,而且每个服务节点都应该有个权重值,如果所有节点

的权重值一样时,它们的流量分配就是均匀的,如果每个节点的权值较小,它被客户端选中的概率也会比

较小。设计示例代码如下:

class RPCNode{
    String addr;   //服务端的地址
    int weight;    //节点权重
}

class RPCCluster{
    RPCNode[] nodes;   //节点的列表
    Node random();   //按权重随机挑选节点
}

二、容灾 Failover

如果有一个服务节点挂掉时,客户端需要采取一定的策略避免请求失败,比如可以重试,但是不能进行无

线的重试,要有一定的重试策略

3yafkn.jpg

一个可行的方案是当节点挂掉时,将失效的节点摘除,放置的失效的节点列表中;然后每隔一段时间检查

失效的节点是否恢复了,如果恢复了,那就从失效的节点中移出,重新加入有效节点的列表中;当然也不能仅

依据一次的检测就判断节点是否有效,可以通过检测一个时间段内的出现的错误数量判断,如果错误数量过多

那就说明了真的失效了,这也是为了避免部分网络问题的原因

三、降权法

我们可以为每个服务端节点赋一个权值,改变权值就可以改变节点的相对流量了;如果某个节点出现了一次

错误就对该节点进行降权,错误次数越多,降权降得越快,最终可以到达一个最小值,但是无论如何,每个节

都还有翻身的机会。被降权的节点只要有一次调用成功,权值就会恢复正常

一个非常简单的策略就是当服务端节点错误时进行权重减半,比如从1024开始减半,一直到1,当恢复时

可以进行权重翻倍

四、服务发现

如果服务端可以支持动态扩容,那么它的稳定性和高可用性就会更高。当系统的负载比较高的时候,我们

可以通过添加节点的方式减轻压力。但是就像前面设计的静态RPC服务地址列表,当节点增加时,必须要修改

客户端的配置重启才能生效,但是生产环境怎么可能重启配置这时候服务发现的技术就上台了

服务发现技术就是服务裂变变更时,客户端可以快速地收到这些信息,从而调整自己的工作状态,这样无

需进行重启就可以完成服务的扩容和缩容

3y04fI.jpg

示例代码如下:

class ServiceDiscovery(object):
    def register_service(self,name,addr):
        pass
    def get_services(self,name):
        pass
    def on_services_changed(self,name):
        pass

服务发现技术依赖于服务之间中间节点,它接受服务的注册、提供服务的查找、以及服务列表变更的实时

通知功能,一般使用高可用的分布式配置数据库作为解决方案,如zookeeper和etcd,具体功能如下:

  • 服务注册:服务端节点在启动时将自己的服务地址注册到中间节点

  • 服务查找:客户端启动时去中间节点查询服务地址列表

  • 服务变更通知:客户端在中间节点上订阅依赖服务列表的变更时间,中间节点负责将变更信息实时通知给客户端