请问微服务架构下,有什么方式能确保消息队列在同一个服务集群只有一个个体收到事件?

之前的提问 中,有提到我想利用消息队列机制来达到各服务解耦

借由某种广播机制,在订单建立完成后,由订单服务发出「订单建立成功」的广播,告诉其他服务有订单建立。库存服务接收到广播后就会扣除库存,并再次发出「库存扣除成功」的广播,由订单服务再次接收。而其他不相干的服务就会忽略广播。

但碰到一个问题:在 K8S 的架构下可能同一个服务会出现多个实例(Pod),那我要如何确保各服务能确实收到事件,且不会重复触发?

目前我得到几种解决方案,但各有一些无法解决的问题,或实作上不知从何下手,方案分述如下:

  1. 在 AWS 中,可使用 SNS 发送事件,再由 SQS 服务接收事件,由各服务从自己的 SQS 领取事件,但我们云端选择 GCP
  2. 在 GCP 中有 Pub/Sub,但可能会有多台服务实例作为 Subscriber,无法确保不会重复触发
  3. Redis 本来就有提供 Pub/Sub 功能,但问题跟(2)一样
  4. 用某种方式将 Event 同时发送到同一台 Redis 的不同 DB,各服务监听不同的 DB,因事件被一服务实例领取后就会暂时锁住,所以可以确保不会重复触发
  5. 用某种方式将 Event 同时发送到不同 Redis,各服务从自己的 Redis 领取事件,同(4),因事件被一服务实例领取后就会暂时锁住,所以可以确保不会重复触发

请问有人碰过类似的状况,或了解微服务架构,能给我一些指导建议吗?

Leo
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 5
LearnKuJ

如果能做到操作是幂等的,那么处理多次也没有关系。

再来说说不幂等的怎么处理。笼统的来讲就是做一个全局的存储,记录哪些消息已经执行过了或正在执行。核心原理就是获取一个锁。

具体实现起来也是一个麻烦的事,细节很多,稍有不慎就会死锁,或者提前释放锁。

7年前 评论

當然鎖是一個好方法,但就如 @TimJuly 大所說,實現起來很麻煩

  1. 若是在各微服務自己實現鎖,就容易跟其他服務產生耦合
  2. 若是設計一個全域用來控制鎖的服務,又會大幅增加系統複雜度

所以我才會希望用我文中的方式,用 Laravel 本來就可以做到的方法來解決

7年前 评论
LearnKuJ

@leochien Laravel自带的处理方法会在任务超时(有可能已经执行成功)的时候重复执行。

7年前 评论

@TimJuly 之前沒有考慮到這個可能
請問 Tim 大對鎖的設計有什麼建議的方式嗎?

7年前 评论
LearnKuJ

@leochien

只是有这个可能,但是发生的几率不大,后续再对账吧。

锁感觉一句两句说不完啊,而且我自己理解的也不是很透彻。

7年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!