分布式事务超时:失败返回不代表没有提交

📅 2026/7/5 19:03:09
分布式事务超时:失败返回不代表没有提交
分布式事务超时失败返回不代表没有提交一、超时是最容易误判的状态分布式事务里客户端收到超时不代表事务一定失败。请求可能已经到达协调者也可能部分参与者已经提交只是响应丢了。把超时简单当失败重试可能造成重复写、状态反转或外部副作用。分布式系统里超时通常表示未知而不是失败。二、区分结果状态stateDiagram-v2 [*] -- pending pending -- committed pending -- aborted pending -- unknown unknown -- committed unknown -- aborted业务接口要能表达 unknown 状态并提供查询最终结果的方式。只返回 success 或 failed会逼调用方做错误假设。transaction_result: success: committed failed: aborted timeout: unknown require_query_api: true超时后的第一步应该是查状态而不是盲目重试。三、幂等键必须前置如果业务允许重试就要在第一次请求时携带幂等键。协调者和参与者都要能识别同一个业务请求避免重复执行。CREATE UNIQUE INDEX uk_request_id ON payment_order(request_id);幂等不是只在接口层做判断数据库约束也要兜底。否则并发重试下仍可能穿透。四、补偿要基于事实失败补偿不能凭客户端感受执行。比如扣款请求超时如果直接发起退款可能在原扣款尚未确认时引入更复杂状态。应先查询事务日志、参与者状态和外部系统回执。timeout_handling: query_transaction_log: true query_participants: true retry_with_idempotency: true compensate_after_confirmed: true还要设置超时层级。客户端超时、网关超时、事务协调者超时、参与者超时应有明确关系。外层超时太短会制造大量 unknown。最后监控要统计 unknown 比例。unknown 上升说明系统正在失去确定性哪怕最终大多提交成功也会让业务逻辑变复杂。日志设计也要服务状态确认。每个阶段都要记录事务 ID、幂等键、参与者、状态版本和最后更新时间。超时后排查时如果只能看到一条网关 504就无法判断事务到底走到哪里。transaction_log: transaction_id: required idempotency_key: required participant_state: required state_version: required updated_at: required对于外部副作用例如发券、发消息、调用支付渠道更要用 outbox 或可靠消息模式承接。数据库事务提交和外部调用之间没有天然原子性超时会把这个缺口放大。最后文档要明确调用方策略。哪些错误可重试哪些需要查询哪些必须人工处理。分布式事务的稳定性不只在服务端也在调用契约里。测试也要模拟响应丢失。只测服务端返回成功或失败覆盖不到最危险的未知状态。可以在提交后丢弃响应、延迟回包、重复发送请求确认幂等和查询接口真的有效。timeout_test_cases: drop_response_after_commit: true retry_same_idempotency_key: true query_final_state: true五、总结分布式事务超时要按 unknown 处理通过幂等键、状态查询、事务日志和事实补偿降低风险。失败返回不代表没有提交。先确认事实再决定重试或补偿。