内容: 记录分布式架构中如何判断服务节点是否存活
场景:
很多判断注册中心节点存活的机制是注册中心摘除机制,服务消费者以注册中心中的数据为准,
当服务端节点有变更时,注册中心就会把变更通知给服务消费者,服务消费者就会调用注册中
心来拉取最新的节点信息。
可能的问题:
这种机制在大部分情况下都可以工作得很好,但是在网络频繁抖动时,服务提供者向注册中心
汇报心跳信息可能会失败,如果在规定的时间内,注册中心都没有收到服务提供者的心跳信息,
就会把这个节点从可用节点列表中移除。更糟糕的是,在服务池拥有上百个节点的的时候,
每个节点都可能会被移除,导致注册中心可用节点的状态一直在变化,这个时候应该如何处理呢?
解决方法:
1、心跳开关保护机制:
在网络频繁抖动的情况下,注册中心中可用的节点会不断变化,这时候服务消费者会频繁收到服务
提供者节点变更的信息,于是就不断地请求注册中心来拉取最新的可用服务节点信息。当有成百上
千个服务消费者,同时请求注册中心获取最新的服务提供者的节点信息时,可能会把注册中心的
带宽给占满,尤其是注册中心是百兆网卡的情况下。所以针对这种情况,需要一种保护机制,
即使在网络频繁抖动的时候,服务消费者也不至于同时去请求注册中心获取最新的服务节点信息。
一个可行的解决方案:
就是给注册中心设置一个开关,当开关打开时,即使网络频繁抖动,注册中心也不会通知所有的
服务消费者有服务节点信息变更,比如只给10%的服务消费者返回变更,这样的话就能将注册中
心的请求量减少到原来的 1/10。
代价:
它会导致服务消费者感知最新的服务节点信息延迟,原先可能在10s内就能感知到服务提供者
节点信息的变更,现在可能会延迟到几分钟,所以在网络正常的情况下,开关并不适合打开;
可以作为一个紧急措施,在网络频繁抖动的时候,才打开这个开关。
2、服务节点摘除保护机制:
服务提供者在进程启动时,会注册服务到注册中心,并每隔一段时间,汇报心跳给注册中心,
以标识自己的存活状态。如果隔了一段固定时间后,服务提供者仍然没有汇报心跳给注册中心,
注册中心就会认为该节点已经处于“dead”状态,于是从服务的可用节点信息中移除出去。
如果遇到网络问题,大批服务提供者节点汇报给注册中心的心跳信息都可能会传达失败,
注册中心就会把它们都从可用节点列表中移除出去,造成剩下的可用节点难以承受所有
的调用,引起“雪崩”。但是这种情况下,可能大部分服务提供者节点是可用的,仅仅
因为网络原因无法汇报心跳给注册中心就被“无情”的摘除了。
这个时候就需要根据实际业务的情况,设定一个阈值比例,即使遇到刚才说的这种情况,
注册中心也不能摘除超过这个阈值比例的节点。
* 这个阈值比例可以根据实际业务的冗余度来确定,通常可把这个比例设定在 20%,
就是说注册中心不能摘除超过 20% 的节点。因为大部分情况下,节点的变化不会
这么频繁,只有在网络抖动或者业务明确要下线大批量节点的情况下才有可能发生。
而业务明确要下线大批量节点的情况是可以预知的,这种情况下可以关闭阈值保护;
而正常情况下,应该打开阈值保护,以防止网络抖动时,大批量可用的服务节点被摘除。
小结一下:
心跳开关保护机制:是为了防止服务提供者节点频繁变更导致的服务消费者同时去注册中
心获取最新服务节点信息;
服务节点摘除保护机制:是为了防止服务提供者节点被大量摘除引起服务消费者可以调用的节点不足。
可见,无论是心跳开关保护机制还是服务节点摘除保护机制,都是因为注册中心里的节点信息是随
时可能发生变化的,所以也可以把注册中心叫作 "动态注册中心"。
另外一种思路:
服务消费者并不严格以注册中心中的服务节点信息为准,而是更多的以服务消费者实际调用信息来
判断服务提供者节点是否可用。这就是 "静态注册中心"。
静态注册中心:
心跳机制能保证在服务提供者出现异常时,注册中心可以及时把不可用的服务提供者从可用节点列表
中移除出去,正常情况下这是个很好的机制。
但是仔细思考一下,为什么不把这种心跳机制直接用在服务消费者端呢?
因为服务提供者是向服务消费者提供服务的,是否可用服务消费者应该比注册中心更清楚,因此可以
直接在服务消费者端根据调用服务提供者是否成功来判定服务提供者是否可用。如果服务消费者调用
某一个服务提供者节点连续失败超过一定次数,可以在本地内存中将这个节点标记为不可用。并且每
隔一段固定时间,服务消费者都要向标记为不可用的节点发起保活探测,如果探测成功了,就将标记
为不可用的节点再恢复为可用状态,重新发起调用。
这样的话,服务提供者节点就不需要向注册中心汇报心跳信息,注册中心中的服务节点信息也不会动
态变化,也可以称之为静态注册中心。
* 采用服务消费者端的保活机制,事实证明这种机制足以应对网络频繁抖动等复杂的场景。
代价:
当然静态注册中心中的服务节点信息并不是一直不变,当在业务上线或者运维人工增加或者
删除服务节点这种预先感知的情况下,还是有必要去修改注册中心中的服务节点信息。
比如,在业务上线过程中,需要把正在部署的服务节点从注册中心中移除,等到服务部署完毕,
完全可用的时候,再加入到注册中心。还有就是在业务新增或者下线服务节点的时候,需要调
用注册中心提供的接口,添加节点信息或者删除节点。这个时候静态注册中心有点退化到配置
中心的意思,只不过这个时候配置中心里存储的不是某一项配置,而是某个服务的可用节点信息。
需要注意的点:
1、注册中心的主动心跳探测不应作为客户端摘除不可用服务端节点的依据,而是要作为参考值,
比如将这种探测信息发给客户端,客户端在负载均衡时,将这种疑似问题节点降权重或作为备用
节点,这样可能会更好
2、相对于动态注册,静态注册的方式把探测任务分散到了服务消费者,在增加服务消费者工作量
的同时,再考虑一个问题:如果某个服务被多个消费者调用,那么该服务提供者会收到大量探测
请求,但这是不必要的消耗,影响服务方提供服务的能力