请教后端们关于分布式事务的实践
大约有这几个问题:
当前使用/曾经使用的分布式事务的方案是什么?
你觉得比较好的方案是哪种?(综合考虑 “对架构复杂度提升”,”对代码可读性的影响“,“对程序员写代码的心智负担提升”等等)
综合下来,做这件事划算吗?是让你更轻松了,还是让你更累了?
如果你加入了一家新公司,当前业务需要引入分布式事务,你会选择哪种方案?
我看过网络上的理论文,但希望得到有真实实践过的后端同学们的分享,而不是全文背诵网络上的文章,这样就没有意义了。
非金融相关行业。
目前团队里涉及到分布式且具有事务性的东西,大多是同步接口创建任务、任务异步执行、任务异常自动重入的流程搞的。基本也没用到消息。
蹲一个
两步提交,后来优化流程干掉了,感觉这个不是啥好设计
绝大部分场景都用不上分布式事务的,还不如搞 mysql 集群
分布式事物加大了复杂性吧,建议最终一致性
如果你加入了一家新公司,当前业务需要引入分布式事务,你会选择哪种方案?
先考虑能不能用最终一致性处理,多系统的异常能不能用回滚解决。实在不行再考虑实时分布式事务。
如果一家公司之前没有相关积累和经验,贸然上所谓的“分布式事务”的方案,大概率后面要踩不少坑
最烦的不是分布式事务的实现,而是万一事务出问题导致数据不一致要怎么处理,要不要手工改数据来兜底,烦。
必须分布式事务 95%以上场景就是个伪命题,架构师/总体组/CTO 动动脑子设计好就可以完全不用
不会是天天吧
用 dtm 这是目前比较好的解决方案 我们公司三年前我主推在使用 没有出现任何问题
坚决不搞分布式事务,因为这玩意没法搞
用 DTM
你的意思不要分布式存储?只要是分布式数据库绕不开分布式事务吧
我们之前用了 seata ,后面业务太重了,大部分业务都改成基于消息队列的最终一致性。但是有些业务也有问题,举个云闪付的例子,支付后可以抽奖,但是因为是异步处理,跳转到抽奖界面基本上都没法直接抽,必须等一会刷新再抽。
正常,用分布式事务的话,要加入中间协调结点,如果是事务 SQL 可能回滚 还要写补偿的 SQL ,不知道 seata 能不能自己生成补偿的 SQL ,我早年看过 seata 相关的技术文章,说他们可以基于 DAO 层 自己补写回滚补偿的 SQL
最后 大部分都会采用消息队列达成最终一致性,如果代码有问题也可以修复后 进行补偿操作,
没法直接抽,可以让前端轮询一下,轮询成功前 按钮变灰色就行,服务端查询的压力稍微大点,这不是啥问题,查询压力 做集群扩缩容 比较容易
不过我用过云闪付,当时就是无法立即抽,我猜测就是消息队列没消费完
直接用 RPC 然后做分布式事务 很麻烦,主要还是处理事务回滚补偿的代码,如果有基于 SQL 层面自动分析 编写回滚补偿的话,可以考虑接受
看了一下 seata 有一个 AT 模式,可以自动回滚补偿,有相关的实践经验介绍一下么
所有的分布式事务都可以基于消息补偿机制,另外分布式事务 伸缩性很差,上游流量多,下游要跟着一起扩容,上游出了问题 下游死一大片,服务可用性很差,而且没法伸缩
真实的实践就是
80%的公司 搞微服务就压根没有这个概念,就是 RPC 调用,上下游不一致了,数据出问题了,程序员自己动手修数据,我待过的小公司都是如此,哪怕我在携程之前一个小 BU 也是靠手动修数据
剩下里面 80%的公司 会用消息队列去做,你可以用携程订一个酒店试试,他们就是先创建订单,然后支付,修改订单状态-为已支付,然后通过消息去扣库存,库存扣好了之后,会通知订单更改状态->已占用库存,APP 端 你支付完之后 是可以看到有一个轮询 订单状态的动作
你如果强行要把 订单->支付扣减->库存扣减 变成一个分布式事务,那就非常麻烦,首先上下游的伸缩性就完全没有了,毕竟流量一来,就都得跟着扩容,其实对于用户来讲,支付完成后,是可以等待一会 看到库存占用成功与否的,甚至从业务上你可以 加一个 库存扣减失败后,订单状态 跟 扣款退款的业务流程
搞分布式事务只有一种情况:刷 kpi 。真实事求是的做设计,根本不可能有分布式事务的适用场景。
- 要求单个请求强一致性:单进程内用数据库事务实现
不要求强一致性:用消息队列异步事件链实现最终一致性
我司用的就是 seata 的 AT + TCC ,用他是因为这个项目最初就有而且是老前辈们手写出来的,已经屎山了。总结下来就是能不用就不用分布式事务,只要模块拆分的够好绝大部分情况是不需要的,少部分需要的用消息队列做
- 简单介绍一下我对 AT 的理解,就是在这个模式下,你等于无数据库的原生事务去执行,也就是你的每一条 sql 都会立即落库,如果发生了回滚,seata 有一份修改前的镜像用来回滚。
- 这时候你就会问那回滚的时候被别的业务修改了怎么办,seata 会根据主键有一个全局锁,如果多个分布式(加粗)事务同时修改同一行能正常阻塞等待,因此这里就是有坑,代码那么多总会有只开了本地事务没开分布式事务的情况,这时候 seata 就会回滚失败,然后人工处理
- 同时我司某些表还存在近似于全表删除的业务,这种情况下有可能甚至把 seata-server 直接打挂
java 文档里有写 一个 char 由两个自己组成 但一个 utf8 汉字由三个字节组成 为什么这样赋值没事? char a = '我'; 问了一下 deepseek …
8 年果粉,因为单位要求换成了 Windows ,目前电脑配置: Thinkpad T14P 2024 CPU:Intel(R) Core(TM) Ultra 9 185H 2…
RT ,用途:1 、测试 android 软件使用。2 、电话卡多了两张,保号用。 全平台使用苹果很久了(丐版收集者),出于上面原因,想买个性能够用的安卓机。 个人对小米( o…