首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅析多服务在分布式系统下多事务通信处理机制方案

浅析多服务在分布式系统下多事务通信处理机制方案

原创
作者头像
粲然忧生
发布2022-08-01 21:38:16
4050
发布2022-08-01 21:38:16
举报
文章被收录于专栏:工程师的分享工程师的分享

分布式系统间的事务处理,一直是一个有意思的课题,这里有很多的文章去分析,这里笔者也有些思考,下面主要从消息队列、消息通道的角度说下自己的思考:

本着由易至难、由抽象到具体的原则,首先定义下一个简单业务场景:

假定有一个平台,里面有微服务A,微服务B,两个服务均提供外部接口,一个负责更新资源,一个负责提供资源服务,可以看到,由于两个服务存在关联(比如,A更新资源后,需要通知B拉取最新的资源),所以需要一定的内部通信机制,这是一个比较常见的平台服务场景,如图

当然这里可以再复杂一下,把分布式的因素加进来,为了方便举例说明,这里只将微服务B变为分布式的微服务,如图:

第一个要解决的问题:选择什么样的内部通信机制:

内部通信通道有很多个选择,比如HTTP、RPC、Redis、Kafka(类似的数据队列)、数据库

其中,同步的有:HTTP、RPC、Redis,异步的为:Kafka(类似的数据队列)、数据库,由于系统希望能够实时提供最新的资源服务,故选择同步通信机制

从服务间通信方式上,一般使用RPC比较多,特别是RPC支持跨语言的通信后,迅速成为业界的新宠,也是比较成熟的方案

但由于微服务A和微服务B都有外部服务,所以服务的部分接口是对外开放的,而使用HTTPRPC服务,会增加内部服务对外化的风险(事实上,在复杂环境部署上,这样的金手指的案例很多),所以这里并不一定是第一选择

再看下这个场景,微服务A资源的更新了,只需要告知微服务B一声“要更新了”即可,而不是将最新的资源直接传过去,是比较简单的提醒通信,这样的通信比较轻量,即使在高并发下,也不太涉及边界数据竞争情况处理。那自然而然就会想到:Redis

场景就变成了这样的:

第二个要解决的问题:如何使用Redis做通信

redis作为通信方式有很多中,在分布式系统下最经典的场景就是分布式锁,即各个分布式的服务抢redis的唯一“锁key”赋值:

这种,基本上把redis作为外延内存来使用,把“锁”作为几个服务的“全局变量”,适用于同服务内部的简单通信,故不适用于这里。

另外一种是创建一个list,通过push和pop的方式获取内容:

似乎可以,但这里存在一个严重的问题,即不支持重复消费:消费者拉取消息后,这条消息就从 List 中删除了,无法被其它消费者再次消费,即不支持多个消费者消费同一批数据,在分布式系统下无法满足,也不能选择这里

还有一种,则是比较经典的发布—订阅者模式

它正好可以解决前面提到的第一个问题:重复消费,即多组生产者、消费者的场景

所以场景再次更新:

当然,看到这里,可能会有疑问,直接将最新的资源从微服务A给到微服务B可以吗?

答案是否定的,因为Pub/Sub 最大问题是:丢数据

特别是在以下三个场景中:消费者下线、Redis 宕机、消息堆积

这样就会对服务的稳定性造成比较大的挑战,所以还是需要持久化存储,同时要做资源更新的兜底任务:

第三个要解决的问题:收到信息后应该怎么做

从这个场景下,可能会觉得,收到信息就去更新资源就好了,其实这里是有坑的

刚才我们模拟的是微服务B是分布式服务,事实上,微服务A也可能是分布式服务,场景变成:

同时,这个通信机制是服务之间的约定,作为接收方,要天然不信任信息的频次和有效性,对应下来就是三种不信任:

1.信息发送的频次

2.信息的重复性

3.信息的丢失性

针对第三种,不仅仅是发送方的问题,也可能是redis的问题,所以需要一个定时拉取资源的兜底方案

针对第一种,拉去最新资源可能是一个耗时耗资源的操作,所以不能频繁拉去

针对第二种,重复的拉去也会导致资源消耗的浪费

所以针对第二种和第一种,就需要对接收的数据,进行防抖和去重,这里可以根据业务的需要进行整合,比较经典的方案是:

加一个定时器,判断即X秒内,微服务B收到需要更新范围Y的资源,这里就可以一定程度内避免了前两种情况

第四个要解决的问题:收到信息后的事件处理与服务内部事件处理资源抢夺怎么办

上图可以看到,通过数据整合和去重,可以降低事件处理的频次,降低资源的消耗

但在微服务B,可能不只一个事件通信,可能多个事件通信都用到了事件处理X(或者用到事件处理X的部分资源),也可能服务本身也会用到事件处理X(或者用到事件处理X的部分资源),由于收到信息的时间不可控,所以这里的事件处理X的资源使用时间也不可知,可能会造成资源抢夺,如下图:

这里,有两种解决方案:

一种是在公共资源和公共逻辑加锁,但这样增加了逻辑的复杂度,如果涉及读写锁等概念则会更加复杂

还有一种是将多个事件处理放入队列,这样也可以避免问题的发生

建议选后者,即:

最后,事实上,这里还可以更加复杂场景,我这里也是抛砖引玉额,如果有想继续的同学,欢迎交流

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一个要解决的问题:选择什么样的内部通信机制:
  • 第二个要解决的问题:如何使用Redis做通信
  • 第三个要解决的问题:收到信息后应该怎么做
  • 第四个要解决的问题:收到信息后的事件处理与服务内部事件处理资源抢夺怎么办
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档