08 | 服务发现:到底是要CP还是AP?
我们为什么需要“服务发现”?
从高可用的角度出发,在生产环境中,服务提供方通常会以集群的方式对外提供服务,集群中的IP地址随时可能发生变化,因此我们需要一本“通讯录”来及时获取对应的服务节点信息,维护“通讯录”以及或者节点信息的过程,我们称之为“服务发现”。
服务发现包括2个核心模块:
- 服务注册:在服务提供方启动的时候,将对外暴露的接口注册到注册中心中,注册中心将这个服务节点的IP和接口保存下来。
- 服务订阅:在服务调用方启动的时候,去注册中心查找并订阅服务提供方的IP,然后缓存到本地,并用于后续远程调用。
我们为什么不采用基于DNS的服务发现机制?
我们来看一下DNS查询流程。
它存在的两个主要问题:
- 如果服务节点的IP端口下线了,服务调用者能否及时摘除服务节点?
- 如果之前已经上线了一部分服务节点,这时突然对这个服务进行扩容,那么新上线的服务节点能否及时接收到流程呢?
为什么VIP方案也不能用于服务发现?
VIP方案如下所示。
它主要有以下几个问题:
- 搭建负载均衡设备或者TCP/IP四层代理,需要额外成本。
- 请求流程都经过负载均衡设备,多经过一次网络传输,会额外浪费性能。
- 负载均衡添加节点和摘除节点,一般都需要手动添加,当大批量扩容和下线时,会有大量的人工操作和生效延迟。
- 不能支持更灵活的负载均衡策略。
基于ZooKeeper的服务发现机制的工作流程是怎样的?
基于ZooKeeper的服务发现结构图如下。
它的工作流程如下:
- 服务平台管理端现在ZooKeeper中创建一个服务根路径,在这个路径下面再创建服务提供方目录和服务调用方目录。
- 当服务提供方发起注册时,会在服务提供方目录中创建一个临时节点,节点中存储该服务提供方的注册信息。
- 当服务调用方发起注册时,会在服务提供方目录中创建一个临时节点,节点中存储该服务提供方的注册信息。
- 当服务提供方目录下有节点数据发生变更时,ZooKeeper就会通知给发起订阅的服务调用方。
基于ZooKeeper的服务发现有什么问题?
当有超大批量的服务节点在同时发起注册操作,ZooKeeper集群的CPU使用率会飙升,导致ZooKeeper集群无法工作。
这本身就是ZooKeeper的性能问题,当连接到ZooKeeper的节点数量特别多,对ZooKeeper的读写操作会特别频繁,而且当ZooKeeper存储的目录达到一定数量时,ZooKeeper就会变得不稳定,CPU使用率持续升高,直到宕机。
ZooKeeper的一大特点就是强一致性,集群中的每个节点的数据每次发生变更操作时,都会通知其他节点同时执行跟新,这样它就要求每个节点的数据能够实时的完全一致,从而导致了ZooKeeper集群性能的下降。
基于消息总线的服务发现机制的工作流程是怎样的?
基于消息总线的服务发现流程图如下:
它的工作流程如下:
- 当有服务上线,注册中心节点收到注册请求,服务列表数据发生变化,会生成一个消息,推送给消息总线,每个消息都有一个整体递增版本。
- 消息总线会主动推送消息到各个注册中心,同时注册中心也会定期拉取消息。对于获取到消息的在消息回放模块里面回放只接受大于本地版本号的消息,小于本地版本号的消息直接丢弃,从而实现最终一致性。
- 消费者定于可以从注册中心内存拿到指定接口的全部服务实例,并缓存到消费者的内存中。
- 采取推拉模式,消费者可以及时地拿到服务实例增量变化情况,并和内存中的混存数据进行合并。
通过消息总线的方式,我们就可以完成注册中心集群间数据变更的通知,保证数据的最终一致性,并能及时地触发注册中心的服务下发操作。
服务发现的特性是允许我们在设计超大规模集群服务发现系统的时候,舍弃一致性,更多的考虑系统的健壮性,因此,在实际工作中,最终一致性是更为常用的策略。