求教,有状态的分布式系统应该如何设计

106 天前
mawen0726  mawen0726

应对业务扩张,将服务拆分并支持横向扩展,现在拆了共 a,b,c 三个服务出来,然后这三个服务要设计成可以随时横向扩展。其中有如下调用链路

然后 c 是主要处理业务的服务,会上分布式锁,加上处理时间长,会后台执行并执行完通知上游来做其他业务操作,业务操作之后才能解锁。

因为一个业务只能在一个 c 中执行,所以解锁要找到对应的 c 。比如 a 执行业务分配到节点 1 的 c,后续交互都要找节点 1 的 cb是批量执行业务,这一批都要到同一个c中执行完。

目前设计方案是将 c的 IP 和业务 id 写到 redis ,然后通过 redis 确定业务在哪个 c 节点上面跑着。然后要在业务处理过程中,查看状态都通过 redis 查对应 ip 再去调用服务。

比如批量任务中,a 要确定哪个 b 节点承接了这个业务,b 节点确定哪个 c 节点正在处理这批次业务。

感觉这种设计不是很好,想请教下还有没有更优雅的做法

可能描述的有点复杂,大概意思是

怎么记录在多个节点时,知道这个任务在哪个节点上,并且应用之间相对不耦合

2788 次点击
所在节点   程序员  程序员
46 条回复
k9982874
k9982874
106 天前
为什么要把问题搞这么复杂,为什么不用消息队列
tairan2006
tairan2006
106 天前
这很简单,你改成 pub/sub ,比如 mqtt 。接到任务的节点会自己订阅相关 topic ,其他的节点不会订阅。你发布任务的时候也无需关心到底目的地在哪。
JasonGrass
JasonGrass
106 天前
我的理解:a 执行业务分配到节点 1 的 c ,执行完成之后,C1 就把中间结果保存到数据库或者 Redis ,得到一个 key,
后面 a 要继续处理这个业务,随便找一个 c 的节点,把 key 给 c ,然后继续处理。

感觉是业务拆得还不够彻底?理想情况是,把业务拆成一步一步执行的,
执行完第一步,丢到消息队列,中间结果(如果有比较大的中间结果)保存到 redis 或者数据库,下一个服务从消息队列中拿到任务,然后继续跑,这样才好真正的横向扩展。
mawen0726
mawen0726
106 天前
@k9982874
消息队列用了,但是用来处理业务中产出的各种数据实时推送...
没想好记录任务在哪个节点这个层面怎么用...
mawen0726
mawen0726
106 天前
@tairan2006 貌似跟 1 楼提的消息队列方式很像,我思考一下怎么设计
k9982874
k9982874
106 天前
不是,你为什么关心认为在哪个节点
a 有任务扔进队列,c 去捡了执行,执行完了再扔个消息,a 受到走完后面流程,就这么简单的事
mawen0726
mawen0726
106 天前
@k9982874
因为 c 在执行任务的时候,上了锁,锁定了某个资源,因为处理时间长,锁定时间久
代码在写的时候,不是常规的写法....
lock.lock
try{
dosomething()
}
finally{
lock.unlock
}


而是起了个线程来上锁,等 a 确定完业务执行完,再去通知持锁的 c 解锁。因为用的 redisson 的 lock ,所以要找回对应的节点 c 才能解锁...
mawen0726
mawen0726
106 天前
@JasonGrass
感觉再拆就不好维护了...
不过可能是我没拆好,感觉还得思考下
mawen0726
mawen0726
106 天前
@k9982874
不过感觉可以按这种方式再想下怎么改,确实可能设计复杂了
1402851639
1402851639
106 天前
感觉你这个耦合这么重是不是拆的就有问题呢。。
1402851639
1402851639
106 天前
我觉得你更应该解释一下是什么条件限制了必须在同一个实例上,去考虑能否在请求中将关键信息传递过去,又或者 redis 暂时存一下,而不是 b 服务去循环将请求打到同一个 c 上面?
yeqizhang
yeqizhang
106 天前
@1402851639 我也觉得,这样拆到底解决了啥问题,我感觉瓶颈都在数据库了,那还要解决分布式的事务问题
wateryessence
wateryessence
106 天前
一致性哈希?
cowcomic
105 天前
1 ,当时为什么要拆,从描述看 abc 的耦合很严重,而且是双向依赖,这不拆更合理
2 ,如果一定要拆,那我理解可以把 C 看成一些工作节点,把 C 向上依赖的部分再拆出来变成 C 的下游,首先保证链条是单向的,AB 变成纯上游,C 变成总业务入口,这样看能不能消除 C 的状态变成无状态的
3 ,如果消除不了,那就 C 前面架消息队列,由 C 决定要哪些请求,如果并发不是很大的话,就直接表记录,如果并发很大,那这个整体的系统功能就很有问题,重新梳理吧
czsas
105 天前
可以借鉴一下 temporal/Cadence 这种 workflow 框架
nuk
105 天前
给每个任务加一个路径栈
server
105 天前
temporal
wenjun19931112
105 天前
想办法把有状态的服务,转换为无状态的服务。
而不是优化有状态服务的分布式处理逻辑。
Plutooo
105 天前
@mawen0726 #7 redisson 的 lock 不是基于线程的吗,当你的 a 通知 c 可以解锁以后相当于一个新的请求,新的请求怎么去解锁之前那个线程的锁
RightHand
105 天前
有状态的,去做复杂均衡啊。干嘛非要上无状态的微服务

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1097140

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX