前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
返回 AI 情报前线
All News · 全部资讯8773
  • GraphRAG生产环境实体重复问题及免费修复方案
  • JSON提示词Runner bug验证:200次重跑结论依然显著
  • 传统 API 网关为何无法保护 AI Agent 及解决方案
  • AI Agent 事故响应:滚动消失前应记录的关键数据
  • 字节跳动训练10万亿参数大模型对标Anthropic
  • MasterGo MCP Server 打通设计工具与 IDE:减少上下文切换认知损耗
  • Node.js AI Agent 工具超时:超时机制设计与模型可见性
  • AI助手为何总是答非所问:RAG系统的版本地狱
  • 我在 Claude Code 用了一周十亿 token?97% 是缓存
  • 我把 croniter 移植到 Rust 拿了 228/228,但这个数字什么也证明不了
  • 用代码量化品牌在 AI 搜索引擎中的可见度:GEO 扫分工具
  • 多模态模型的真正瓶颈在最弱编码器
  • Cloudflare 解读 Agent 时代的 Bot 行为评分体系
  • SvelteKit 配置可直接写入 vite.config.js
  • Cloudflare 统一 AI Gateway 与 Workers AI,提供统一路由与计费
  • Cloudflare Radar Researcher:用自然语言探索全球互联网流量数据
  • 在 Claude Code 中使用 Kimi K3 省钱提效
  • Matt Pocock 技能套装安装量突破 54 万次
  • 2026 年 AI 模型格局:主要玩家一览及选型指南
  • 电商从 1 到 1000 单的工程架构演进实战
  • AI Agent 让分布式系统双写问题代价飙升
  • Stack Overflow 流量暴跌 78%,AI 编码助手改变开发问题解决方式
  • Flow Render:用async/await思维重构UI交互
  • 我为何不再信任系统提示词的优先级
  • OpenAI GPT-5.6 发布:Sol/Terra/Luna 三层分级,Free 用户默认使用 Terra
  • 用 TypeScript 构建 Image-to-Video 提示词规划 MCP Server 教程
  • 链上 AI Agent 的信任边界设计实践
  • RAG Agent 行动前的人类在环机制设计
  • Uber 四个月烧完全年 AI 编码预算,微软停用付费编码工具
  • GitHub Actions 和 Pages 降级可用性的应对指南
  • 48个prompt改写实例:信息位置影响模型准确率
  • n8n框架:识别AI流水线中的静默错误
  • 你可能不需要专用向量数据库
  • MemoFS:为TypeScript AI Agent打造文件持久化记忆层
  • Awareness:本地优先的AI Agent记忆工具,R@5达96%
  • 研究实验:AI Agent 能做开放式研究吗?
  • 单 Go 协程跑 8 Gbps 视频流:雷群问题实战
  • Cloudflare CI SDK 发布:TypeScript 替代 YAML 定义流水线
  • AI 能写代码后,程序员的品味才是剩余价值
  • 用 Node.js + Playwright 构建自主式 AI 浏览器 Agent
  • Unsloth 本地微调大模型:VRAM 减半、速度翻倍
  • 本周5条真正落地的AI工作流经验
  • Inngest 对比 Diagrid Catalyst:企业级 Agent 平台选型
  • MCP应用测试与调试:生产级实战指南
  • 五大科技公司联合制定AI Agent插件开放标准
  • 我做了llms.txt但从没有任何爬虫访问过
  • Anthropic Mythos 5 在安全测试中自主发动供应链攻击
  • Agent 账单杀手:被忽视的 Cache-Hit 计费逻辑
  • Token价格周报:NVIDIA Nemotron 3 Super涨价70%
  • 实战:如何为ERP集成构建AI Agent
  • 企业AI Agent生产级五大挑战
  • 已加载 51 / 8773
8.0
热点
AI SCORE
技术实践2026-08-07 20:14

AI Agent 让分布式系统双写问题代价飙升

dev.to · AI#分布式系统#AI Agent#工程实践
Editor brief · 编辑速览

LLM 时代 Agent 重试机制放大双写问题——重复事件可触发欺诈调查、支付冻结与重复退款,黑五夜一单可达数百万欧元。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

AI 智能体正在让一种古老的分布式系统 Bug 代价更高

双重写入问题早在 LLM 出现之前就存在了。如今,一条重复的事件可能引发欺诈调查、支付冻结、退款或金融执行。

黑色星期五晚上 23:57,一个全球电商平台批准了一笔 240 万欧元的商家提现。

账本提交了交易。应用发布了 PayoutApproved。然后请求超时了。

没有服务一定宕机。数据库是健康的。消息代理也可能是健康的。网络在几毫秒后恢复。所有仪表盘仍然是绿色的。

然而系统失去的东西比可用性更危险。

它失去了确定性。

时序图,展示支付服务成功提交提现到账本数据库,然后向代理发布 PayoutApproved 事件。确认超时,导致支付服务无法确定事件是否被接收——造成两种风险:如果不重试则可能错过风险审查,如果重试则可能重复投递。

代理收到事件了吗?

如果生产者什么都不做,风险系统可能永远不会分析这笔提现。如果生产者重试——而第一次发布实际上成功了——事件可能被投递两次。如果下游执行不是幂等的,相同的业务操作可能被执行两次。

几毫秒的不确定性可以变成一个价值数百万欧元的问题:

操作失败了,还是我们只是未能观察到它成功了?

这不是一个根本上的 Kafka 问题、NATS 问题或 AI 问题。这是一个分布式系统问题。

现代 AI 智能体让它代价更高,因为事件消费者的能力变得更强了。一条重复的事件不再只意味着重复的投影或重复的日志行。它可能唤醒一个负责评估欺诈、建议支付冻结、发起调查、请求退款或调用连接外部金融系统的工具的智能体。

投递语义并没有变差。事件背后的东西变得更强大。

架构需要回答五个问题:

事件在何处成为权威来源?

失败后如何恢复发布?

消费者如何容忍重投递?

业务需要时如何保证顺序?

如何证明一个不可逆的外部效果只发生了一次?

1. 你的代理解决不了双重写入问题

批准一笔提现的服务通常执行两个在概念上相关但存在于两个独立事务系统中的操作:数据库和代理。

流程图,展示"批准提现"分支为两个独立操作:"更新数据库"和"发布 PayoutApproved",由一条虚线连接,标注"不同的事务边界",说明两次写入不是原子的。

没有跨越两个系统的自动原子事务,这产生了三种不同的失败状态:

这就是双重写入问题。代理给你提供了解耦、缓冲、持久化、扇出、重放和故障隔离。它不能给你的是事件与导致该事件存在的数据库状态之间的原子性。这个区别是后续所有内容的基础。

2. Kafka、Redpanda、RabbitMQ 和 NATS 解决的是不同的问题

正确的问题不是"哪个代理最好?"——而是"这个工作负载实际上需要哪些保证?"

Apache Kafka——在长保留期、基于分区的顺序、高吞吐量、重放、流处理和成熟的连接器生态方面表现强劲。自 Kafka 4.0 起,ZooKeeper 模式已被移除,KRaft 成为必选——少了一个运维依赖,但分区、保留期、再平衡和灾难恢复仍然需要精心的工程设计。

Redpanda——广泛的 Kafka 协议兼容性,包括幂等生产者和事务,但运维配置不同。架构边界不变:Redpanda 事务不能使对外部 Postgres 数据库——或银行转账——的写入变为原子操作。

RabbitMQ——仲裁队列、发布者确认、持久化消息、单活跃消费者、流和路由交换,使其非常适合命令、任务分发和工作流编排。

NATS JetStream——结合了低延迟的 NATS 消息传递与持久化、持久消费者、保留期和基于确认的投递。在分布式拓扑、请求-应答工作负载和边缘环境中很有吸引力。

它们中没有一个能独自消除双重写入问题。

3. AI 智能体不创造问题——它们扩大了爆炸半径

双重写入问题比 LLM 早了几十年。重试、重复消息、丢失确认和事件乱序是已有的分布式系统故障模式。改变的是消费者现在能用重复事件做什么。

流程图,展示一条低风险路径:PayoutApproved 事件流向投影消费者,后者更新仪表盘。

如果旧的投影消费者处理了两次重复,且投影是幂等的,影响可能微乎其微。如果同样的重复现在经过一条智能体路径,它可能触发第二次欺诈调查、第二次账户冻结或第二次退款指令。

这并不意味着 AI 智能体天生不安全。它意味着围绕它们的架构必须假设消息会到达多次、智能体会犯错、工具会超时、模型会变化、外部系统会返回模糊的结果。

AI 智能体绝不应该仅仅因为生成了一个看似合理的答案就转移资金。更安全的边界是将推理与执行分离:

流程图,展示 PayoutApproved 触发 AI 风险智能体,后者输出 PayoutRiskAssessed 到策略和审批服务。策略服务分支到"释放提现"(在限额内)或"需要人工审核",两者都流入幂等支付执行器,后者写入账本。

AI 建议。策略决定。系统执行。

智能体分析、分类、解释和建议。确定性服务评估限额、权限、职责分离和合规性。只有在那之后,幂等执行器才执行外部效果。

4. CDC 不仅仅是遗留系统的逃生舱

企业系统很少从零开始就干净。银行、保险公司和电信运营商通常依赖早于事件驱动架构主流化之前数年构建的 ERP 和结算引擎。将它们重写为发出领域事件可能风险太大。

变更数据捕获(通常指 Debezium)观察事务数据库日志并捕获已提交的变更,而不触碰遗留应用。

流程图,展示带有 PAYMENT_BATCH 表的遗留 ERP 数据库通过基于日志的 CDC 流入 Debezium,然后进入转换/反腐败层,输出三个稳定的领域事件:PayoutApproved、BeneficiaryChanged 和 SettlementCompleted。

陷阱:一行变更不等于自动成为领域事件。STATUS = 'A' 可能意味着已批准、待审核或一个在遗留系统之外没有意义的内部转换。如果下游服务必须理解物理表和隐晦的状态码,数据库模式已悄然成为了一份公共契约——而且是脆弱的。

一个转换层保护组织其他部分免受遗留系统物理表示的影响。CDC 在迁移之外也是战略性的:它可以填充搜索索引、数据仓库、读模型——而且最重要的是,它可以捕获一个 Outbox 表,传输应用刻意设计的事件而非技术噪声。

5. 事务性 Outbox 修复事件的诞生

一个新的支付服务在同一时刻知道两个事实:提现改变了状态,描述该变更的事件必须最终被发布。它不执行两次独立写入,而是在一次本地事务中记录两个事实。

BEGIN;

UPDATE payouts
SET status = 'APPROVED', version = 17
WHERE id = 'pay_7f9q';

INSERT INTO outbox (
    event_id, aggregate_id, aggregate_version,
    event_type, payload, occurred_at
) VALUES (
    'evt_01K...', 'pay_7f9q', 17,
    'PayoutApproved', '{...}', CURRENT_TIMESTAMP
);

COMMIT;

流程图,展示业务事务进入包含"更新提现行"和"插入 Outbox 事件"的单个数据库事务边界,两者都流入提交步骤,随后中继或 CDC 进程读取 Outbox 并发布到代理。

  1. Outbox 不能保证精确一次

序列图,显示中继从 Outbox 表读取待处理事件,向 Broker 发布并收到确认。中继在将事件标记为已发布之前崩溃。重启后,中继再次读取相同的待处理事件并第二次发布,展示了安全崩溃恢复导致的多发重复,而非 Broker 故障。

这里的重复不是 Broker 损坏的证据——它是安全从不确定性中恢复的正确结果。

不要在"传递恰好发生一次"这个假设上构建正确性。要让消费者做到:重复传递不会重复业务效果。

工作的不变量:

记录原子一次。传递至少一次。效果应用一次。

Kafka 和 Redpanda 在定义的事务边界内提供精确一次语义。NATS 在配置的窗口内提供发布去重。这些都不能自动让 POST https://external-bank/pay 变成精确一次——Broker 控制不了银行。

  1. 幂等性在 Broker 之前就开始了

Outbox 解决了一种形式的重复,不是全部。如果客户端在丢失响应后重试 POST /payouts,服务器可能在 Outbox 参与之前就创建了两个 payout。

每个事件都带有一个不可变的 eventId。消费者在应用效果之前记录该 ID:

BEGIN;

INSERT INTO inbox(event_id, received_at)
VALUES ('evt_01K...', CURRENT_TIMESTAMP)
ON CONFLICT DO NOTHING;

IF event_was_inserted THEN
    UPDATE payout_projection ...;
END IF;

COMMIT;

如果 evt_01K... 再次到达,Inbox 约束会阻止重复的本地效果。仍然有一个边界:外部世界。

  1. 幂等性必须到达最终副作用

如果最后一跳——实际的银行转账——缺乏唯一性保证,内部去重毫无意义。

流程图,显示事件 ID 流入 Payment Executor,后者使用事件 ID 作为幂等性键调用 External Provider。响应分支为成功(更新账本为 PAID)或超时/不确定(设置状态为 UNKNOWN 并触发 Reconciliation Job,循环回去再次检查响应)。

超时意味着 UNKNOWN,不是 FAILED。如果没有目的地的唯一性、与 Provider 的幂等性合约或协调循环,"精确一次"就不是保证——而是乐观。

  1. 顺序是业务属性,不是 Broker 的营销卖点

"消息是有序的"是错误的说法。真正的问题是:相对于什么的顺序?

图示对比预期的事件顺序(v17 PayoutApproved、v18 PayoutHeld、v19 PayoutReleased)与实际传递顺序(v19 PayoutReleased 先于 v18 PayoutHeld 到达),两者都标有警告符号,表示产生的状态无效。

处理 v17 → v19 → v18 即使最终每个消息都到达,也可能产生无效状态。事件信封应携带 aggregateVersion,以便消费者检测过时事件、重复和序列间隙。

NATS subject 是路由地址;Kafka partition 是显式的存储和顺序边界——它们不等价。NATS 中的确定性路由需要一个不透明实体键一致地映射到分片:

finance.payouts.eu.s042.pk_7f9q.approved

流程图,显示不透明的 payout 键哈希到分片 s042,路由到 Serial Worker 或 Consumer,后者检查 aggregateVersion。如果事件有序,效果被应用;如果检测到间隙,事件被保存在重排序缓冲区中。

并行 worker 保持到达顺序,不是完成顺序——如果外部副作用依赖顺序,仅靠存储顺序无法保护不变量。

  1. 边缘和多区域系统需要明确权威

必须能在断网时存活的分支、区域网关或边缘部署需要一个本地数据库和本地 Outbox,在连接恢复后同步一次。

流程图,显示 Edge 域拥有本地数据库馈送本地 Outbox,与中央全局事件平台之间被红色"网络中断,同步阻塞"节点分隔,一旦连接恢复问题解决即同步到中央平台。

NATS leaf 节点不会自动将本地数据库转变为无冲突的离线存储。架构仍需定义:每个实体哪个系统是权威的、如何解决冲突、如何检测间隙、本地磁盘满时怎么办、以及协调如何完成。

本地可用性加上最终全局收敛——而非独立于网络的全局一致性。

  1. 参考架构

大流程图,显示两条并行轨道。遗留系统轨道:ERP 或 Core Ledger 到 CDC 到翻译层到稳定领域事件。新服务轨道:Payment Service 到包含业务表和 Outbox 的单一本地事务,馈送给 Relay 或 CDC Router。两条轨道在中央 Broker(Kafka、Redpanda、NATS JetStream 或 RabbitMQ)汇合,向账本投影、AI 风险 Agent、审计服务和通知服务扇出。AI 风险 Agent 生成 PayoutRiskAssessed,馈送给策略和审批服务,然后是幂等支付执行器,然后是账本,然后是外部 Provider,然后是协调。

基本构建块:权威事务源、原子 Outbox、可靠发布、持久传输、不可变事件标识、幂等消费者、需要顺序处的顺序、确定性策略边界、幂等外部执行和协调。Broker 是其中的一个组件——不是架构本身。

  1. 事件信封是契约的一部分
{
  "eventId": "evt_01K...",
  "eventType": "PayoutApproved",
  "aggregateId": "pay_7f9q",
  "aggregateVersion": 17,
  "schemaVersion": 3,
  "occurredAt": "2026-08-07T10:57:01Z",
  "correlationId": "corr_8x7b",
  "causationId": "cmd_9c3a"
}

eventId 建立不可变标识。aggregateVersion 强制序列正确性。correlationId 和 causationId 端到端连接业务流。一旦 AI 智能体参与,这个元数据就变得至关重要。

  1. AI 决策需要证据,不只是日志

"Payout blocked" 不是足够的审计跟踪。严肃的系统必须能够重建完整决策路径:

AI 输出是决策过程中的证据——它不应自动成为财务真相的来源。账本、策略服务和权限模型仍然是权威的。治理定义了最小化、哈希、保留和访问控制——目标是可重现性和问责制,不是监控。

  1. 可观测性应该衡量正确性,不只是可用性

显示绿色 CPU 和绿色运行时间的仪表板可能完全错过开篇场景中的故障——没有不可用,系统处于不确定状态。

追踪:CDC 延迟、发布延迟、消费者延迟、重投递率、重复检测计数、Inbox 冲突、序列间隙、死信增长、Outbox 积压、协调差异、Agent 失败、策略拒绝和外部超时率。

最危险的状态不是 service = DOWN。而是:

payment = UNKNOWN

这值得作为可协调的业务对象获得一等可见性——不是通用错误计数器里的一行。

  1. 安全必须经受事件管道

事件系统广泛复制信息,这使得粗心的标识符代价高昂。不要在 topic/subject 名称中嵌入账号、卡号或身份证号——它们会泄露到日志、指标、追踪和仪表板。

❌  finance.account.447819002343.payment
✅  finance.payouts.eu.s042.pk_7f9q.approved

传输中加密和静态加密、细粒度访问控制、模式治理、受控回放、死信处理和数据驻留控制是不可妥协的。没有治理的持久性只会让错误存续更久。

  1. 不要把 Broker 选择变成宗教

架构应该遵循不变量。不变量不应该追随产品标识。

  1. 精确一次的真正含义

"这个 Broker 支持精确一次吗?"很少是有用的问题。有用的问题是:在哪里精确一次?

在一个 Kafka 事务内?在一个数据库内?跨 broker 和 Stripe?跨应用和银行?跨两个区域在分区期间?边界越宽,这个短语就越难捍卫。

只记录一次业务意图。
通知至少送达一次。
检测重复投递。
每个业务效果只应用一次。
对结果仍不确定的事物进行对账。

恰好一次不仅仅是传输层的属性。业务正确性是端到端的属性。

AI 并不废除分布式系统。智能体仍在网络上运行。工具仍会超时。数据库仍独立提交。消息仍可能重复。

AI 改变的是信息与行动之间的距离。当智能体系统获得操作权限时,分布式系统正确性变得更加重要,而非相反。智能体的可靠性主要不是一个提示工程问题——最重要的保证仍然存在于原子性、幂等性、排序、授权、隔离、可审计性和对账中。模型只是一个组件。

事务性发件箱模式通过在同一个本地事务中记录业务状态和发布意图,解决了异步系统中最难的边界之一。CDC 或中继将这个意图传输到 broker。Broker 提供持久化投递。收件箱模式和不可变事件标识符让消费者可以容忍重投。聚合版本保留业务排序。幂等性密钥保护命令和外部操作。策略服务将概率推理与确定性授权分离。对账解决了网络使结果不确定的情况。

AI 智能体并没有创造这些分布式系统问题。它们让忽视这些问题的代价更高。

一个重复事件现在可以传播得更远。重试可以激活更有能力的软件。不确定的结果可以触发影响客户、账户、基础设施或金钱的决策。

这就是为什么现代智能体架构不应该从询问哪个模型最聪明或哪个 broker 最快开始。它应该从业务不变量开始:

每笔资金流动必须有不可变标识符,来自授权的事务状态,在发布失败时存活,容忍重投,保留所需的业务顺序,通过确定性策略控制,以幂等方式执行,并保持可对账和可审计。

然后在一切看起来正常但确认永远不到来时,问出真正重要的问题:

你的系统能证明同一笔付款不会重复离开吗?

不是 Kafka 是否保持在线。不是数据库是否保持在线。不是你的 AI 智能体是否产生了正确的解释。

而是当网络停止告诉你发生了什么时,架构是否保持了现实。

Apache Kafka Documentation

Apache Kafka 4.0 — ZooKeeper Removal, KRaft-only Architecture

Debezium Outbox Event Router

Debezium Server + NATS JetStream Support

NATS JetStream Delivery & Acknowledgements

NATS JetStream Publication Deduplication

NATS Deterministic Subject Partitioning

NATS Leaf Nodes and JetStream Domains

RabbitMQ Queues, Quorum Queues, Streams

Redpanda Transactions & Kafka Compatibility

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
电商从 1 到 1000 单的工程架构演进实战
下一篇
Stack Overflow 流量暴跌 78%,AI 编码助手改变开发问题解决方式