在微服务系统中,服务的粒度一般都会被拆分的非常细,单个方法都有可能作为一个独立的服务发布。所以使用微服务架构的业务系统,生产环境上常常会运行着非常非常多的服务节点。这就带来了一个问题,我们使用微服务架构后,虽然实现了服务的解耦,提高了系统稳定性和开发效率,但在享受这些收益的同时也带来了管理和维护成本的增加。注册中心作为微服务架构的核心基础服务,其重要性也就不言而喻了。
注册中心都需要具备哪些功能呢?
通过以上功能分析,可以看出注册中心核心功能是服务提供方节点数据的存储与查询,可以理解为一个简单的存储系统。那么作为存储系统我们又需要关注哪些特性呢?
提到存储我们首先就会想到如何保证所存储数据的可靠性(不丢失),为了保证数据可靠一般都会冗余存储(主从或多副本的分布式存储)。数据冗余存储就需要进行节点间的数据同步,同步就会带来数据的一致性问题,是强一致还是最终一致?其次我们还需要考虑系统的可用性,系统内部分节点出现故障导致数据同步异常时是否还可以继续对外提供服务?
分析到这里相信很多同学都已经想到分布式系统的核心理论基础——CAP定理。即在分布式系统中C(数据一致性),A(服务可用性),P(分区容错性)只能满足其二。具体细节我们就不做分析了,本文我们只是用这个结论来分析注册中心应该采用什么样的技术选型。
从功能上看,满足注册中心功能需求可以作为技术选型的开源产品有很多,常见的选型对比如下表:
从上面的对比表格可以看到,从功能角度讲,无论实现方式如何,各系统都是可以作为注册中心来使用的。最大的不同点在于它们在CAP上的选择,换句话说,我们的注册中心到底应该选择满足CP还是AP呢?这就需要结合注册中心的应用场景来分析了。
以服务消费方上线后拉取服务提供方节点列表为例,注册中心接收到请求时的状态可能有两种情况:
针对第一种情况直接返回即可这里不做分析。如果注册中心收到拉取请求时正在处理数据变更(有新的服务方节点注册或有节点下线),这时是应该立刻向消费方返回节点列表,还是等待处理完变更后再返回呢?我们分别分析下两种处理方式的影响,就不难得出结论了。
由于注册中心尚未处理完数据变更,各存储节点上的数据可能不一致,服务消费方拉取到的服务提供方节点信息可能与实际情况不符,但无非是以下两种情况:
正常情况下需要服务消费方短暂的等待,待注册中心各节点数据处于一致性状态后得到返回结果,看上去也没有什么影响,但问题在于,如果注册中心各节点发生了网络分区,短时间内无法达到数据一致性状态,这样就不能返回数据,消费方无法获取到服务提供方节点信息,就无法正常发起调用,这个影响就相当大了。
通过上面的分析发现,问题的本质在于发生网络分区时注册中心应该保证A还是C,即注册中心应该是CP还是AP。对于服务发现场景来说,即使注册中心的不同节点保存的服务提供者信息不尽相同,也并不会造成灾难性的后果。因为对于服务消费方来说,能消费才是最重要的,拿到不正确的服务提供方节点信息好过因为无法获取服务节点信息而不去消费。
所以,对于服务发现而言,AP胜过CP。当然这还取决于业务场景和RPC客户端容错能力,有可能由于RPC客户端实现不够健壮,获取到错误的节点也可能带来灾难性的后果。但理想情况下对于服务发现来讲注册中心应该是AP模型。
刚才是站在服务发现的角度分析,接下来我们站在服务注册的角度分析。如果注册中心发生了网络分区,CP场景下新的节点无法注册,新部署的服务节点就不能提供服务,站在业务角度这是我们不想看到的,因为我们希望将新的服务节点通知到尽量多的服务消费方,不能因为注册中心要保证数据的一致性而让所有新节点都不生效。对于服务注册 AP的效果也是好于CP的。
所以AP模型的注册中心能够更好的满足大多数场景的业务需求。
在上面的注册中心功能需求中提到了节点保活功能,这个功能一般是通过服务提供方与注册中心保持心跳来实现的。注册中心可以将心跳超时的节点剔除,看上去没有什么问题。但是,在异常情况下,这个功能也是要谨慎处理的。例如注册中心系统内发生网络分区时,已注册的服务提供方的心跳数据无法及时同步到注册中心内所有存储节点,这样会造成在大量节点的心跳超时,此时如果注册中心将这些节点剔除,就可能会造成非常严重的后果,极端境况会导致服务消费方拉取不到可用的服务节点,导致业务瘫痪。所以发生网络分区时,注册中心的保活策略也需要相应的降级,以保证系统的可用性。
综上所述,在大多数分布式业务场景下,注册中心的可用性是高于数据一致性的。我们在设计注册中心时,要更多的考虑如何保证系统的可用性,当然这也不是绝对的,还需要结合实际应用场景做出合理的选择。
思考:Zookeeper为什么可以当做注册中心,在什么场景下会不适用呢?