引言在分布式系统里最危险的不是失败而是“我以为失败了其实成功了。”本文从一个朴素却深刻的认知出发——网络调用结果有三态——讲清楚业界最成熟的工程化解决方案。一、先纠正一个根深蒂固的错误认知很多开发者写 HTTP / RPC 调用代码是这样的try{ResultresultbClient.doSomething(req);if(result.isSuccess()){// 成功逻辑}else{// 失败逻辑}}catch(Exceptione){// 失败逻辑和上面合并log.error(调用 B 失败,e);returnResult.fail();}看起来没问题但它隐藏了分布式系统最致命的问题网络调用不是二态成功 / 失败而是三态✅ 成功❌ 失败❓ 未知UNKNOWN把UNKNOWN 当 FAIL是以下问题的根源资金错账重复扣费库存超卖状态不一致二、什么是“未知态”典型场景如下A 端表现B 端真实状态SocketTimeoutException可能成功 / 可能失败 / 可能处理中Connection reset很可能已成功响应丢了HTTP 504还在执行HTTP 502已执行响应丢失熔断 fallback可能已成功反序列化失败已返回 200共同点A 不知道 B 做没做。错误处理的后果重复扣款A 回滚B 已扣钱库存超卖A 重试B 扣两次消息重复A 重发状态错乱A 失败B 成功三、核心思想承认三态收敛未知业界黄金法则接口幂等 三态区分 异步反查 对账兜底四件事缺一不可。四、第一板斧接口幂等最核心4.1 什么是幂等同一个请求执行 1 次 执行 N 次4.2 四种主流方案① Idempotency-Key推荐开放 APIPOST /v1/charges Idempotency-Key: xxxResultcachedcache.get(key);if(cached!null)returncached;lock(key);ResultresultdoBiz();cache.set(key,result);returnresult;优点通用、标准化Stripe / GitHub② 业务唯一键最推荐内部服务UNIQUEKEYuk_biz_id(biz_id)try{insert();}catch(DuplicateKeyExceptione){returnqueryOld();}优点简单 强一致③ 状态机if(statusPAID)return;update where statusPENDING;优点语义清晰④ Token 防重GET token → Redis POST → DEL token 成功才执行推荐组合业务唯一键 状态机五、第二板斧调用方区分三态try{returnSUCCESS;}catch(Timeout|ConnectExceptione){returnUNKNOWN;}catch(Http5xxe){returnUNKNOWN;}catch(Http4xxe){returnFAIL;}分类规则类型归类超时 / 连接错误UNKNOWNHTTP 5xxUNKNOWNHTTP 4xxFAIL业务异常FAIL正确处理方式switch(state){caseSUCCESS:提交;break;caseFAIL:回滚;break;caseUNKNOWN:标记处理中反查;}❗ 永远不要把 UNKNOWN 当 FAIL六、第三板斧异步反查B 必须提供接口GET /status?bizIdxxx返回SUCCESS/FAIL/PROCESSING/NOT_FOUNDA 的反查逻辑for(record:processingList){respquery();switch(resp){SUCCESS→ 完成FAIL→ 失败NOT_FOUND→ 真失败PROCESSING→ 下次再查}}工程要点指数退避5s → 30s → 5min最大重试次数防止压垮 BNOT_FOUND 语义清晰七、第四板斧对账最终兜底T0 实时对账每分钟扫描异常数据T1 离线对账流程拉 A 数据拉 B 数据diff结果A 有 B 无 → 冲正A 无 B 有 → 补单状态不同 → 修复 支付系统标配清算文件 对账八、完整流程A 下单 → 调 B ↓ SUCCESS / FAIL / UNKNOWN ↓ UNKNOWN → PROCESSING ↓ 异步反查 ↓ 确认 or 进入对账九、加分项Outbox Pattern核心思想本地事务 消息发送 原子化Transactional插业务表 插 outbox 表定时任务发送消息 失败重试优点不丢消息自动重试最终一致十、协议层补充协议能力gRPCDeadline CancelHTTP/2RST_STREAMRSocket双向流⚠️ 协议不是根本解法十一、避坑清单常见错误❌ 幂等没加唯一索引❌ Redis 挂了无降级❌ 没有 UNKNOWN❌ 没有对账❌ 反查打爆下游❌ 无限重试❌ 4xx 也重试十二、总结分布式系统的本质承认不确定性