今天在一个朋友的群里聊起 RPC 这类框架,刚好我也在写 RSF(一个分布式RPC框架)对于分布式环境来讲,一个服务会有多个副本,调用端在多个副本之间如何抉择是一个很明显的问题。因而注册中心应运而生。 缓存
但是我心中一直有一个疙瘩,总以为注册中心这个东西大可没必要要的。因而索性设计一个套去中心化的解决方案,用以去中心化的分布式 RPC 框架的设计。 服务器
先说一下中心化的分布式 RPC 工做方式, 通常状况下“注册中心”负责接受服务上线时的心跳请求,而且“注册中心”会维持一个活跃的服务列表。当有消费者上线时“注册中心”会告诉消费者可用的服务列表。而后消费者会本身去轮询调用不一样服务地址已完成调用。 网络
若是某一个服务节点当掉了“注册中心”就检测不到节点的心跳因而会通知消费端服务下线。其实“注册中心”要作的一件事情就是监控死掉的服务。要想知道死掉的服务有两种办法:一种心跳监听、另外一种主动发现。 架构
“注册中心”走的是心跳监听的路线。若是遇到刚死的服务“注册中心”还没来得及通知,那调用发起的确定还要在作一次异常重试。因而在客户端又多了一个主动发现的容错方案。 框架
我以为这是彻底重复的工做是不必的,二者留一个就能够了。何况客户端去调用远程服务时候,既然都要去发现服务是否真的死掉,为嘛还要搞一个“注册中心”? 分布式
并且“注册中心”一旦挂掉,新上线的机器没法及时更新到 IP 列表,这样的影响会更大。为了不这种事情,咱们又把“注册中心”作了热备。 这种设计是否是过重了呢? 优化
因此我以为必定要去中心化! spa
BT 软件下载,有一个很好的思想。 设计
BT在下载软件你只要知道一个种子地址,剩下的客户端会根据种子地址去发现更多的可用源来下载文件。咱们可使用这种思想让服务端在启动时经过一个源自动发现更多的服务可用地址。 资源
可是这里有一个问题,咱们先回归生产环境。一个庞大的集群可能会有几十万个服务在跑,这个已是很大规模了。你不能要求这几十万的服务之间相互P2P的调用通讯,这不科学。
因而我想到,只保留 BT 思想里种子的概念,而后用爬虫的机制让机器与机器之间相互分享本身的地址列表和服务列表。这样一来台机器只须要知道我想要什么,而后到本地地址池里去找本身的资源就能够了。
本地地址池的创建能够首先经过种子服务器预热,只要获取到一个可用的IP地址列表在本地缓存起来。第二次启动时就彻底不须要源了。
这个就是自动发现的原理。剩下的就是你只须要一台种子服务器,负责提供初始的 IP 地址列表就好了。一旦完成第一次启动RPC客户端从源中取到了更多可用的源,那么就再也不须要这个最初的源服务器了。从而也就完成去中心化。
至于死去的服务, 每台客户端在遇到调用长时间无响应时候会自动去作降权处理。当超过必定次数以后自动将这个死掉的IP地址处理掉。
有朋友会问,你的种子服务器一旦挂掉怎么办?
要知道在这种去中心化的架构里,种子服务器不是中心。任何一台服务器都是种子服务器。你只须要让最早启动的两台服务器之间知道彼此的存在,后面启动的服务器都会纷纷加入到这个网络中,分享彼此的地址本。这样一来每台服务器都是“中心”了。
当选定的种子服务器当掉了怎么办?
每台服务器在启动的时候,都会在本地创建一个缓存的地址本。里面会有不少备选服务地址能够去链接,这些地址都是种子服务器,因此只要你服务成功跑起来一次那么就什么都不怕了。
服务挂掉当请求超时对服务地址作降权处理。长期再也不活跃的服务 IP 会被剔除。这样一来就清爽不少了。
另一个问题也会涉及到注册中心,那就是“服务治理”,所谓服务治理是指一大堆策略性的配置,比方说流量管控、服务降级、服务热下线、服务监控以及多机房路由优化。
而我以为这些东西最总落实在注册中心上的只能是一些策略性的配置,真正执行策略的仍是分散各个节点上的服务器。所以注册中心在其中的做用也仅仅是统一策略管理和策略的分发。
若是去中心化的这些策略分发,能够利用服务器之间分享的方式来传播变动。这样一来你只要把策略下发到其中一台服务的机器上,它便会为你传播到全部机器上,服务治理的问题也就解决了。