幂等是指一次和多次请求某一个资源应该具有同样的作用。
什么是分布式的幂等
首先,我们来设想以下几个场景:
通常,为了满足高可用、高性能和高可扩展的特性,分布式系统拥有众多服务节点,但是却容易导致服务调用链冗长复杂,服务节点之间网络通信复杂度指数级增加,一处轻微网络故障就可能导致整个服务异常。
同时,考虑到硬件设备自身故障的可能性,所以分布式系统面临一个共同的问题:一个消息(任务)可能会被重复消费。因此,如何确保同一个消息单次消费和多次重复消费具有相同的效果,也就是消息的幂等性成为一个热点问题。
其他常见的分布式解决方案
以上是其他常见的幂等解决方案,往往在不同的业务场景下会采用不同的方法。由于我们的主要业务是分布式存储,IO 从 Client 到 Server 的链路都不会很长,所以我们参考 Token 机制,实现了一套“新”机制来处理业务场景里存在的幂等问题。
不同状态的消息处理
如图所示,这是一个简单的任务系统,Server 成功执行了 ① 发送来的命令,但是并没有收到对应的结果。这是因为有网络因素的存储遇到问题,Client 都需要去重试任务,以排除网络不稳定带来的影响,但是在不同情况下,Server 收到重试消息时,需要有不同的应对方案。这时,可能会出现以下三种情况:
第一种情况,Server 并没有收到对应的消息,因为有网络不稳定的情况存在,Client 是需要去重试的,这时 Server 会重新收到消息并且进行处理,正常处理之后返回对应的结果。
第二种情况,Server 收到了对应的消息,还正在处理,由于其他因素导致任务执行时间过长。这是因为任务仍然在执行,所以为了保证幂等,我们需要等之前的任务执行完成后,再获取其执行的结果返回给客户端。
第三种情况,Server 收到了对应的消息,并且已经处理完成,但是网络因素导致 Client 没有收到 ② 的结果,Server 收到重试的请求之后,直接获取已经收到结果返回给 Client。
为了做到上面的功能,我们需要有一套合理的机制来保存已经收到的消息状态,并且需要在能够判断消息已经被 Client 收到结果时清理这个状态,这里我们引入了 SeqNumber 来做到这些事情。
SeqNumber 的机制
我们每次的请求都会带着一个之前已经完成的请求序号 ACK 和当前序号 Seq,Server 在处理时会根据 Seq 来判断当前消息的状态,保证一个 Seq 不会被执行多次。同时,会释放 ACK 对应的序号,因为只有在这个时候才能保证 Client 已经正确的完成了对应的请求。
我们在 Client 端有两个队列 finished 和 running,分别存有正在执行的和已经完成的任务 ID。在 Server 端有一个 map,保存了所有未清理的消息(包括正在执行,执行完成)。
我们一个请求有以下几个步骤:
总结
分布式系统是一个非常庞大且复杂的系统,幂等只是其中非常重要且复杂的问题,在分布式系统的构建中,不同的系统对于幂等有着不同的需求,希望这篇文章能够对大家有所帮助。
留言与评论(共有 0 条评论) “” |