知识卡片

端到端原则与操作标识符实现幂等性

普通读书笔记卡

内容

[[流处理的恰好一次语义微批存档点原子提交与幂等性]]讨论过的重复抑制,其实只在单跳通信里有效:TCP用序列号排序、去重、重传丢包,但这只覆盖单条TCP连接内部——如果客户端提交事务后连接中断,重连重试就已经跳出了TCP重复抑制的范围,若该次操作本身不是幂等的(如”余额+11”这类非幂等的资金转移SQL),重试就可能让钱多转一倍;即便用[[原子提交问题与两阶段提交的机制及两个不归路]]的两阶段提交打破TCP连接与事务的1:1映射,也无法完全杜绝重复,因为终端用户设备到应用服务器之间还有一段网络:用户提交表单后信号中断、没收到响应就手动点了重试,这在Web服务器和数据库看来都是全新的独立请求,常规去重机制在此无能为力。解决办法是让操作具备端到端的幂等性:客户端为操作生成唯一标识符(UUID,或对表单字段做哈希)作为隐藏字段一路带到数据库,靠数据库对该ID列的唯一约束来防止重复生效——这正是1984年Saltzer、Reed、Clark提出的端到端原则的具体应用:只有在通信系统两端应用的知识配合下,某个功能(这里是去重)才能被完全正确实现,把它下放给通信系统本身(TCP、事务、流处理器的恰好一次语义)永远只能得到不完备的版本;这个原则同样解释了为什么以太网/TCP/TLS内置的校验和检测不了软件bug导致的数据损坏,为什么家庭WiFi加密防不住互联网另一端的攻击者——低层功能有用,但不能替代端到端的解决方案。

参考来源

- 位置:《数据密集型应用系统设计》第十二章《数据系统的未来》"正好执行一次操作""抑制重复""操作标识符""端到端原则"(源文件:_epub-src/ch12_split_002.html) - 结论依据:原文用资金转移事务重试导致多转钱、以及Web表单POST超时后用户手动重试的例子说明TCP和两阶段提交的重复抑制范围有限,并引用1984年端到端原则说明只有客户端一路携带请求ID到数据库才能实现真正的端到端去重,直接支撑本卡片结论。 - 原始内容:客户端可以重连到数据库并重试事务,但现在已经处于TCP重复抑制的范围之外了……你需要考虑端到端的请求流……只有在通信系统两端应用的知识与帮助下,所讨论的功能才能完全地正确地实现。