news 2026/10/17 3:59:20

8种分布式事务方案实战指南:从踩坑到选型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
8种分布式事务方案实战指南:从踩坑到选型

1. 这不是理论课,是我在三个高并发系统里踩出来的分布式事务实战手册

“8种常用的分布式事务解决方案”——看到这个标题,你脑子里是不是立刻浮现出PPT里那些带箭头的方框图、一堆缩写词(XA、TCC、Saga、本地消息表……),还有讲师在台上说“大家记住这八种模式,面试必考”?我当年也是这么过来的。直到在某电商中台项目上线前夜,订单创建成功但库存没扣减,用户付款后收不到货;又在某金融结算系统里,一笔跨账户转账最终只完成了借方记账,贷方始终没更新,资金差额卡在中间状态长达47分钟。那会儿我才真正明白:分布式事务不是选择题,是生存题。它不解决“要不要做”,而是“怎么做才不会崩”。今天这篇,不讲教科书定义,不列学术论文引用,只讲我在真实生产环境里用过、压测过、回滚过、半夜被报警电话叫醒后重写的8种方案。它们分别是:两阶段提交(2PC)、三阶段提交(3PC)、TCC(Try-Confirm-Cancel)、本地消息表、发件箱模式(Outbox)、Saga模式(Choreography & Orchestration)、最大努力通知、Seata AT 模式。每一种,我都拆解到数据库连接池怎么配、超时时间设多少、补偿逻辑写几行、日志落盘在哪一级、失败后人工介入点在哪。适合正在设计支付链路的后端工程师、负责订单履约系统的架构师、刚接手遗留分布式系统的运维同学,以及所有被“事务不一致”问题反复折磨过的开发者。你不需要先懂CAP定理,只需要知道:当你的服务拆成5个微服务、数据散在3个数据库、用户点击“立即支付”的那一刻,系统到底在后台做了什么,又可能在哪一步悄悄掉链子。

2. 方案选型不是拼参数,是看它敢不敢接住你最脏的业务场景

2.1 为什么不能只看“一致性等级”就拍板?

很多技术方案对比表格,第一列永远是“一致性级别:强/最终/弱”,第二列是“性能损耗:高/中/低”,第三列是“实现复杂度:简单/中等/困难”。这种对比在会议室里很安全,但在生产环境里就是埋雷。举个真实例子:某社区团购系统初期用TCC模式处理“下单-锁库存-扣款-发券”四步,每个环节都写了Try/Confirm/Cancel逻辑。上线后发现,高峰期锁库存Try操作平均耗时230ms,而业务方要求下单接口P99必须<800ms。于是团队把Try里的库存校验从“查DB+加行锁”改成“查Redis缓存+原子计数器”,看似快了,结果出现大量超卖——因为缓存和DB未实时同步,Try成功但Confirm时DB实际库存已不足。问题出在哪?不是TCC本身错,而是我们忽略了TCC对业务侵入性的容忍边界:它要求每个资源提供者都具备“预留能力”,而库存服务当时根本没设计预留字段,硬加进去导致数据模型撕裂。所以方案选型的第一步,永远不是打开维基百科查定义,而是摊开你的业务流程图,标出三个关键节点:哪个环节失败概率最高?哪个环节失败后人工补救成本最大?哪个环节的上下游系统你根本没法改代码?比如金融类系统,“扣款”失败必须零容忍,但“发短信通知”失败可以容忍几秒延迟;而电商类系统,“创建订单”失败可重试,但“扣减库存”失败必须立即阻断。这直接决定了:强一致性方案(如2PC)可能只适合核心支付链路,而最终一致性(如本地消息表)更适合通知类、日志类旁路操作。

2.2 八种方案的真实战场定位图谱

我把这八种方案按两个维度做了实战分级:业务改造深度(从0侵入到重度改造)和故障兜底能力(自动恢复能力 vs 人工介入强度)。这不是理论推演,而是基于过去三年在6个不同行业系统中的落地反馈整理:

方案名称业务改造深度自动恢复能力典型适用场景我踩过的最大坑
2PC(XA)极低弱单体应用拆库初期,DB同厂商MySQL 5.7下XA事务日志刷盘策略导致主从延迟突增
3PC极低中对可用性要求极高,能接受轻微数据漂移网络分区时PreCommit阶段卡住,协调者无法决策
TCC高强核心资金操作,需精确控制中间态Cancel逻辑未考虑幂等,重复调用导致反向扣款
本地消息表中中跨服务通知(如订单→物流)、异步解耦消息表与业务表不在同一DB,跨库事务失效
发件箱模式中强需要保证“业务操作与事件发布”原子性未配置Debezium心跳间隔,导致binlog位点丢失
Saga(编排式)中强长周期业务(如保险核保、供应链审批)补偿事务执行超时,状态机卡在中间态无人感知
Saga(协同式)低弱服务自治性强,不愿暴露内部状态某个服务升级后事件格式变更,下游无法解析触发补偿
最大努力通知极低弱非核心路径(如推送、邮件、统计上报)重试次数设为3次,第4次失败后彻底丢弃,无告警

注意看最后一列——“我踩过的最大坑”。这不是为了显摆,而是告诉你:每个方案的致命缺陷,往往藏在文档不会写的细节里。比如2PC在MySQL上的坑,官方文档只说“支持XA”,但从不提5.7版本默认innodb_support_xa=ON,但日志刷盘策略在高并发下会让XID持久化延迟,导致从库回放时事务状态不一致。这些,才是决定方案生死的关键。

2.3 为什么Seata AT模式成了新晋网红?它真有那么神?

Seata AT模式常被宣传为“无侵入式分布式事务”,很多团队把它当银弹引入。但我要泼一盆冷水:AT模式的“无侵入”,仅指业务代码不用改,它的底层代价是极高的。AT模式本质是基于全局事务ID的SQL解析+影子表+回滚日志。当你执行一条UPDATE account SET balance = balance - 100 WHERE user_id = 123,Seata会在执行前先查当前balance值(生成undo_log),再执行SQL,最后把旧值和新值都记进undo_log表。这意味着:

  • 每条DML操作额外增加1次SELECT + 1次INSERT(undo_log);
  • undo_log表会随事务量线性增长,某客户单日产生2.3TB undo_log,磁盘IO直接打满;
  • 回滚时需反向解析SQL,遇到UPDATE ... SET col = col + 1这类表达式,无法精确还原,只能靠before_image和after_image比对,一旦中间有其他事务修改同一行,回滚就失败。

所以AT模式真正的适用边界是:业务QPS < 500、单事务SQL < 5条、表结构稳定、能接受undo_log定期归档清理。超过这个阈值,我宁愿上TCC——虽然代码多写300行,但性能曲线平滑,故障点清晰。这也是为什么我在某千万级用户App的积分系统里,最终放弃AT改用TCC:积分变动频繁,但每次变动逻辑固定(加/减/冻结),Try阶段只校验余额和状态,Confirm阶段纯更新,Cancel就是状态回滚,整个链路可控得像呼吸一样自然。

3. 八种方案逐一手把手拆解:从原理到每一行关键配置

3.1 两阶段提交(2PC):教科书里的“理想国”,现实中的“高压线”

2PC的原理一句话:协调者(Coordinator)先问所有参与者(Participant)“准备好了吗?”,都答“OK”再发“提交”指令;任一参与者答“NO”或超时,就发“回滚”指令。听起来完美?问题全在“准备”和“提交”之间的时间窗口里。

实操关键点:

  • MySQL XA配置不是开个开关就行。必须确认innodb_support_xa=ON(5.7+默认开启),但更要检查max_binlog_size和sync_binlog。我们曾因sync_binlog=0导致主库崩溃后,XA事务在binlog里找不到对应记录,从库无法重建事务上下文。正确姿势是:sync_binlog=1+innodb_flush_log_at_trx_commit=1,牺牲一点性能换一致性。
  • 超时时间必须分层设置。协调者等待参与者Prepare响应的超时(建议30s),远小于参与者等待协调者Commit指令的超时(建议120s)。否则会出现“协调者已超时回滚,但参与者还在等Commit”的经典悬挂状态。
  • 日志必须落盘且独立。XA事务日志(mysql-xa-log)不能和普通binlog混存。我们曾把XA日志放在SSD,binlog放在HDD,结果HDD慢导致XA日志刷盘延迟,协调者误判参与者失败。

避坑心得:

提示:2PC在云环境慎用!某公有云RDS的“跨可用区同步”机制会拦截XA PREPARE指令,导致事务永远卡在Prepare状态。上线前务必在目标云环境做XA连通性测试,用XA START 'xid'; INSERT ...; XA END 'xid'; XA PREPARE 'xid';这一套命令跑通再部署。

3.2 三阶段提交(3PC):给2PC加了个“缓冲垫”,但代价是更复杂的脑裂

3PC比2PC多了一个CanCommit阶段:协调者先问“你们有可能提交吗?”,参与者只检查自身状态(不加锁),答“YES”后协调者才进入PreCommit阶段。这减少了2PC中Prepare阶段的资源锁定时间,但引入新问题:网络分区时,部分参与者收到PreCommit,部分没收到,协调者挂了,剩下的参与者该等还是该回滚?

实操关键点:

  • PreCommit阶段必须带超时心跳。我们给每个参与者配置了precommit_timeout=45s,并要求协调者每10s发一次心跳。一旦心跳中断,参与者自动进入“超时回滚”流程,而不是傻等。
  • 最终Commit阶段必须幂等。协调者重启后,需从持久化存储(如ZooKeeper)读取事务状态,对已PreCommit但未Commit的事务重发Commit指令。这里最容易漏的是:重发指令必须带唯一tx_id,参与者收到重复指令直接返回成功,避免二次提交。
  • 日志存储必须跨机房。3PC的日志(记录CanCommit/PreCommit状态)不能只存在协调者本地。我们用etcd集群存状态,确保协调者所在机房整体宕机时,新协调者能从etcd恢复上下文。

避坑心得:

注意:3PC没有解决“脑裂”本质问题,只是降低了概率。某次机房光纤被挖断,协调者所在AZ与多数参与者失联,但与少数参与者保持连接。协调者误判为“多数同意”,发出Commit,而失联的参与者因超时自行回滚。最终数据不一致。结论:3PC适合同城多机房,不适合异地多活。

3.3 TCC模式:把分布式事务拆成“三段业务代码”,可控但费人

TCC的核心是:Try(预留资源)、Confirm(执行业务)、Cancel(释放资源)。它不依赖数据库事务,而是由业务自己保证三个阶段的幂等性和可补偿性。

实操关键点:

  • Try阶段必须做“真预留”,不是假校验。比如扣款Try,不能只查余额够不够,而要冻结对应金额(UPDATE account SET frozen_balance = frozen_balance + 100 WHERE user_id = 123 AND balance >= 100)。否则Confirm时余额可能已被其他事务扣减。
  • Confirm和Cancel必须100%幂等。我们给每个事务ID(tx_id)加了唯一索引,Confirm/Cancel执行前先INSERT IGNORE INTO tx_executed (tx_id, stage) VALUES (?, 'confirm'),成功才执行业务逻辑。
  • 状态机必须持久化。不能把事务状态存在内存或Redis里。我们用一张tcc_transaction表,字段包括tx_id、status(try/confirming/canceling/done)、gmt_modified,每次状态变更都UPDATE ... WHERE status = ?,避免并发覆盖。

避坑心得:

提示:Cancel逻辑最容易写错。某次Cancel写成UPDATE account SET balance = balance + frozen_balance, frozen_balance = 0,但没加WHERE frozen_balance > 0条件,导致frozen_balance为负时,balance被错误增加。正确写法是:UPDATE account SET balance = balance + frozen_balance, frozen_balance = 0 WHERE user_id = ? AND frozen_balance > 0。永远假设Cancel会被调用N次。

3.4 本地消息表:用“空间换时间”,最适合老系统改造

本地消息表的思路极朴素:业务操作和发消息,都写进同一个数据库的两张表,靠本地事务保证原子性;再起一个后台任务,轮询消息表,把消息发到MQ,成功后删消息。

实操关键点:

  • 消息表必须和业务表同库同实例。这是底线!我们曾因DBA把消息表迁到读库,导致业务表更新成功,消息表插入失败,事务回滚,消息永远发不出去。
  • 轮询任务必须带防重和限流。我们用SELECT * FROM msg_table WHERE status = 'pending' ORDER BY id LIMIT 100 FOR UPDATE加行锁,处理完再UPDATE ... SET status = 'sent'。同时用Redis计数器限制每秒最多处理50条,避免MQ积压。
  • 消息体必须包含完整上下文。不能只存order_id,而要序列化整个订单对象(JSON),因为MQ消费端可能需要user_id、amount等字段,而这些字段在消息发送后可能被业务修改。

避坑心得:

注意:消息表的status字段不要用ENUM类型!某次MySQL升级后,ENUM('pending','sent')的排序规则变更,导致ORDER BY status结果错乱,轮询任务跳过大量消息。改用TINYINT(0=pending, 1=sent)一劳永逸。

3.5 发件箱模式(Outbox):基于数据库变更日志的“优雅解耦”

发件箱模式是本地消息表的进化版:业务只写业务表,不碰消息表;通过监听数据库binlog(如MySQL的Debezium),捕获业务表变更,自动生成事件写入outbox表,再由独立服务投递到MQ。

实操关键点:

  • Debezium配置必须开启snapshot.mode=initial且database.history.kafka.topic指向专用topic。我们曾因历史topic复用,导致Debezium重启后从错误位点开始同步,重复投递事件。
  • Outbox表必须有唯一约束。我们设计outbox表结构为(event_id PK, aggregate_type, aggregate_id, event_type, payload, created_time),并在aggregate_id + event_type上建唯一索引,防止同一聚合根的同一事件被重复写入。
  • 投递服务必须支持“至少一次”语义。我们用Kafka的enable.idempotence=true+acks=all,消费端用idempotent_consumer去重。

避坑心得:

提示:Debezium的heartbeat.interval.ms必须小于session.timeout.ms。我们曾设心跳30s,超时45s,结果网络抖动40s,Debezium被Kafka踢出消费者组,重启后从头同步,造成海量重复事件。正确配置:心跳10s,超时30s。

3.6 Saga模式:为长流程业务定制的“柔性事务”

Saga把一个长事务拆成一系列本地事务,每个事务都有对应的补偿事务。分为两种编排方式:

  • Choreography(协同式):各服务通过事件通信,无中心协调者。
  • Orchestration(编排式):由一个Orchestrator服务指挥所有步骤,像交响乐指挥。

实操关键点:

  • 协同式Saga的事件命名必须带版本号。我们用order-created-v1、order-created-v2,避免服务升级后事件格式不兼容。
  • 编排式Saga的状态机必须可视化。我们用Camunda引擎,所有状态流转(如order_created → inventory_locked → payment_confirmed → order_shipped)都在Web界面可查,失败时直接点“重试”或“跳过”。
  • 补偿事务必须有超时熔断。我们给每个Cancel操作设10s超时,超时则标记为compensation_failed,触发人工告警。

避坑心得:

注意:Saga不保证隔离性!某次库存服务在inventory_locked状态时,另一个订单查询库存,看到的是“已锁”状态,但实际该锁可能因后续支付失败而被Cancel。所以业务查询必须区分“可用库存”和“总库存”,前者要减去所有locked状态的量。

3.7 最大努力通知:承认“做不到100%”,但把失败控制在可接受范围

最大努力通知适用于:通知类、日志类、非核心路径操作。它的哲学是:尽最大努力发出去,失败就重试,重试还不成就记录日志,等人工处理。

实操关键点:

  • 重试策略必须指数退避。我们用1s, 3s, 9s, 27s, 81s五次重试,第五次失败后写入notify_failure表,字段包括target_url,request_body,error_msg,retry_count。
  • 通知内容必须可追溯。每次通知都生成唯一notify_id,记录在业务表中(如order.notify_id = 'ntf_abc123'),方便问题定位。
  • 失败告警必须分级。notify_failure表每小时统计失败数,>100条触发企业微信告警,>1000条触发电话告警。

避坑心得:

提示:不要用HTTP重定向做通知!某次第三方服务返回302重定向,我们的HTTP客户端自动跟随,但重定向后的URL不在白名单内,导致通知被防火墙拦截。正确做法:禁用自动重定向,手动处理3xx响应。

3.8 Seata AT模式:让数据库替你扛事务,但得看清它的“隐形负债”

Seata AT模式的魔力在于:你写SQL,它自动解析、生成undo_log、协调全局事务。但这份便利背后,是数据库和网络的双重压力。

实操关键点:

  • undo_log表必须单独建库,且定期归档。我们用sharding-jdbc按月分表,undo_log_202401、undo_log_202402,每月1号凌晨自动归档到冷备库。
  • TM(事务管理器)必须集群部署。我们用Nacos注册Seata Server,3节点集群,避免单点故障。
  • 分支事务必须配置合理超时。@GlobalTransactional(timeoutMills = 30000),但更要配置client.rm.report.success.enable=false,避免大量成功报告冲垮Server。

避坑心得:

注意:AT模式不支持INSERT ... SELECT、UPDATE ... LIMIT等复杂SQL。某次用UPDATE order SET status = 'paid' WHERE user_id IN (SELECT user_id FROM temp_user_list),Seata无法解析子查询,直接抛异常。解决方案:拆成两步,先查ID列表,再循环更新。

4. 实战问题排查:从报警电话到定位根因的完整链路

4.1 场景一:订单已支付,但库存未扣减——如何30分钟内定位?

这是分布式事务最经典的“半完成”问题。我的标准排查链路如下:

第一步:确认事务状态

  • 查订单表order.status = 'paid',确认支付成功;
  • 查库存表inventory.quantity,确认未变化;
  • 查Seata全局事务表global_table,找xid匹配的记录,看status是否为Committed或Rollbacked。

第二步:追踪分支事务

  • 查branch_table,找该xid下的所有分支,重点关注status为PhaseOne_Failed或Unknown的记录;
  • 根据branch_id查undo_log表,看是否有对应记录。若无,说明Try阶段根本没执行;若有,看before_image和after_image是否为空。

第三步:分析日志

  • 在TM日志(seata-server.log)搜xid,看是否有Branch Rollback failed;
  • 在RM日志(应用日志)搜xid,看是否有Lock wait timeout或Deadlock found。

第四步:快速止损

  • 若确认是库存服务Confirm失败,立即执行补偿SQL:UPDATE inventory SET quantity = quantity - ? WHERE sku_id = ? AND quantity >= ?;
  • 同时在branch_table中将该分支status置为Rollbacked,避免Seata重复尝试。

实操心得:我们给所有关键事务加了“健康检查探针”。在订单服务里暴露/actuator/transaction-status?xid=xxx端点,返回该事务的全局状态、各分支状态、最后更新时间。运维同学不用登录服务器,浏览器就能看。

4.2 场景二:Saga流程卡在“支付确认”后,不往下走——是网络问题还是代码Bug?

Saga卡住通常意味着Orchestrator没收到payment_confirmed事件,或收到后没触发下一步。

排查步骤:

  • 查Kafka topicpayment-events,用kafka-console-consumer.sh消费,确认事件已发出且格式正确(含order_id,status: 'confirmed');
  • 查Orchestrator服务日志,搜order_id,看是否有Received payment_confirmed event,若无,检查Kafka消费者组group.id是否配置错误;
  • 若日志有接收记录,但没触发ship_order,查状态机定义,确认payment_confirmed事件是否绑定到正确状态(如paid状态),而非created状态;
  • 最后查state_machine_instance表,看该订单的current_state是否为payment_confirmed,last_event_time是否超时(>5分钟)。

实操心得:我们在Orchestrator里加了“死信队列监控”。所有未被消费的事件,超过30秒自动转入DLQ topic,每天凌晨用Flink作业扫描DLQ,生成报表发给负责人。上线三个月,90%的卡顿问题在发生当天就被发现。

4.3 场景三:本地消息表积压10万条,MQ消费端CPU 100%——是消息体太大还是序列化问题?

消息积压从来不是单一原因。我的排查清单:

  • 查消息体大小:用kafka-dump-log.sh --files /path/to/segment --print-data-log | head -n 100看前几条消息的payload长度。若>1MB,立刻优化:压缩JSON、拆分大对象;
  • 查序列化方式:确认生产者用StringSerializer,消费者用StringDeserializer,而非ByteArraySerializer导致乱码;
  • 查消费端逻辑:在消费方法里加System.currentTimeMillis()打点,看单条消息处理耗时。若>200ms,检查是否有同步HTTP调用、DB查询;
  • 查Kafka配置:fetch.max.wait.ms=500(避免空轮询),max.partition.fetch.bytes=10485760(10MB,匹配大消息)。

实操心得:我们给所有消息加了size_bytes字段,并在消费端做拦截:if (msg.size_bytes > 524288) { log.warn("Large message detected"); return; }。宁可丢弃超大消息,也不让整个消费组瘫痪。

5. 终极选择指南:根据你的系统现状,抄这份配置清单

5.1 如果你正在从单体架构拆微服务

推荐组合:本地消息表 + 最大努力通知

  • 为什么:改动最小,业务代码几乎不改,DBA也熟悉;
  • 配置清单:
    1. 消息表建在主业务库,字段:id(BIGINT PK), topic(VARCHAR), payload(JSON), status(TINYINT), created_time(DATETIME), retry_count(TINYINT DEFAULT 0);
    2. 轮询任务:每5秒执行SELECT * FROM msg_table WHERE status = 0 ORDER BY id LIMIT 50 FOR UPDATE;
    3. 消费端:用Spring Kafka,concurrency=5,max.poll.records=100;
    4. 失败处理:retry_count < 3则UPDATE ... SET status = 0, retry_count = retry_count + 1, gmt_modified = NOW(),否则写入msg_failure表并告警。

5.2 如果你已有多套微服务,且核心链路要求强一致

推荐组合:TCC(核心链路) + Saga(长流程)

  • 为什么:TCC可控,Saga灵活,组合覆盖80%场景;
  • 配置清单:
    1. TCC Try阶段:所有资源预留SQL必须带FOR UPDATE,且WHERE条件包含业务状态(如status = 'active');
    2. Saga Orchestrator:用Camunda,状态机定义存Git,CI/CD自动部署;
    3. 公共组件:统一tx_id生成器(Snowflake),所有日志打点带tx_id;
    4. 监控:Prometheus抓取tcc_try_duration_seconds_count、saga_step_duration_seconds_count,Grafana看板实时展示。

5.3 如果你用云原生技术栈(K8s + Service Mesh)

推荐组合:发件箱模式(Outbox) + Seata AT(非核心链路)

  • 为什么:Outbox天然契合云环境的松耦合,AT用于快速验证新服务;
  • 配置清单:
    1. Debezium Connector:"connector.class": "io.debezium.connector.mysql.MySqlConnector","database.history.kafka.topic": "schema-changes.inventory";
    2. Outbox投递服务:K8s Deployment,replicas=3,HPA基于kafka_consumergroup_lag指标伸缩;
    3. Seata:Server用StatefulSet部署,storage.db指向独立RDS,undo_log表按月分表;
    4. 安全:所有跨服务调用走Istio mTLS,Seata通信走独立Service。

最后分享一个小技巧:无论选哪种方案,在所有事务入口加一行日志:log.info("TX_START xid={}, service={}, method={}", XID.get(), this.getClass().getSimpleName(), methodName);。这行日志能在任何时刻,帮你把散落在10个服务、5个数据库的日志串成一条线。我见过太多团队花三天时间,就为了搞清楚“那个失败的订单,到底走到哪一步了”。而这行日志,成本为零。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 3:58:56

MedVisora本地一键部署:《Science》级RADAR腹部CT分割落地实践

1. 项目概述&#xff1a;这不是一个“装个软件”的事&#xff0c;而是一次医学影像AI落地的实操复盘MedVisora本地一键部署&#xff0c;这个标题里藏着三个关键信号&#xff1a;本地化、开箱即用、临床级模型。它不是又一个跑在Colab上的Demo&#xff0c;也不是需要调参三天才能…

作者头像 李华
网站建设 2026/10/17 3:58:21

Agent与LLM工程实践日报:记忆管理、工具调用与多Agent协作

1. 从一份日报的选题逻辑说起&#xff1a;为什么Agent与LLM的交叉地带最值得盯做技术日报这件事&#xff0c;我坚持了快两年&#xff0c;最大的体会是&#xff1a;选题的眼光比写稿的能力更稀缺。每天铺天盖地的论文、开源仓库、工程博客&#xff0c;如果只是按热度排序搬运&am…

作者头像 李华
网站建设 2026/10/17 3:56:26

KV Cache优化实战:大模型推理显存占用与加速方案详解

1. 先搞懂KV Cache到底在解什么问题做过大模型推理的朋友都知道&#xff0c;自回归生成是一个非常“笨”的过程&#xff1a;模型一次只能吐出一个token&#xff0c;然后把新生成的token拼到已有序列后面&#xff0c;再继续预测下一个token。这个过程本质上是一个无限长的循环&a…

作者头像 李华
网站建设 2026/10/17 3:56:24

从零搭建金融服务网关:账户、交易与对账的工程实践

搞过金融服务项目的人都清楚&#xff0c;真正的难点从来不在“能不能转账”&#xff0c;而在“转完账之后怎么对账、怎么防风险、怎么过审计”。这篇文章记录的&#xff0c;是我们团队从零搭建一套金融服务网关系统的完整过程——它对外统一暴露支付、账户、流水查询等金融API&…

作者头像 李华