知识卡片

事务重试机制看似万能实则四个局限

普通读书笔记卡

内容

[[ACID原子性的本质是可中止性与并发无关]]的核心价值是”中止后可以安全重试”,但重试 远不是万能药,至少有四类局限需要留意。第一,网络确认丢失导致的重复执行:如果事务 实际上已经成功提交,但服务器向客户端确认成功时网络故障,客户端会误以为提交失败而 重试,除非有额外的应用级去重机制,否则事务会被执行两次。第二,过载时重试火上浇油: 如果错误本来就是因为系统负载过大,一味重试只会让问题更严重,需要限制重试次数、 用指数退避、并把过载相关的错误单独处理来避免这种正反馈循环。第三,重试只对临时性 错误有意义:死锁、瞬时故障、网络中断、故障切换这类临时错误值得重试,但违反约束 这类永久性错误重试再多次结果都一样,纯属浪费。第四,事务外的副作用无法随事务一起 撤销:如果事务里包含发邮件这类数据库之外的动作,事务被中止、重试时,之前那次尝试 触发的副作用(比如已经发出去的邮件)不会跟着回滚——如果需要让多个不同系统步调 一致地一起提交或放弃,需要两阶段提交这类专门机制来处理。这四点合起来说明: “事务中止了就安全重试”这个直觉虽然大方向正确,但真正把它落到实处需要考虑幂等性、 限流、错误分类、跨系统副作用这几个维度,不能想当然地当成无脑操作。

参考来源

- 位置:《数据密集型应用系统设计》第七章《事务》"处理错误和中止"(源文件: _epub-src/ch7_split_001.html) - 结论依据:原文列出重试的四类问题:网络确认丢失导致事务被执行两次、负载过大时 重试使问题恶化需要指数退避、只有临时性错误值得重试、事务在数据库外的副作用 无法随中止撤销,直接支撑本卡片结论。 - 原始内容:如果事务实际上成功了,但是在服务器试图向客户端确认提交成功时网络 发生故障……重试事务会导致事务被执行两次……如果错误是由于负载过大造成的,则 重试事务将使问题变得更糟……仅在临时性错误后才值得重试……如果事务在数据库之外 也有副作用,即使事务被中止,也可能发生这些副作用。