架构题目

门诊结算

门诊结算场景下,系统需要在患者结账时完成费用扣减,并同步更新结算状态、费用明细等业务信息,同时生成对应的发药单。该流程既涉及本地资金和业务数据更新,也涉及跨系统交互,因此需要重点解决重复扣费、并发冲突、跨系统一致性和异常恢复等问题。

风险点

  1. 用户重复点击或接口重复调用,导致患者费用被重复扣减
  2. 并发结算时多个请求同时处理同一笔业务,导致状态覆盖或重复处理
  3. 本地事务执行失败,造成费用扣减和业务状态更新不一致
  4. 跨系统交互失败,导致本系统与外部系统状态不一致
  5. 高并发扣减场景下,可能出现余额被扣成负数
  6. 系统在流程执行中途宕机,留下处理中或不一致的中间态数据

架构方案

  • 前端层:对结算按钮增加遮罩、loading、按钮置灰等控制,减少用户重复点击导致的重复请求,但前端防重仅作为体验优化,真正的防重由后端保证。
  • 幂等控制:对结算请求、补偿请求及跨系统回调引入业务唯一流水号,保证同一笔业务重复请求时只处理一次。
  • 并发控制:对结算单采用状态值 + revision 的方式进行乐观锁控制。业务层先校验状态是否合法,数据库 update 时在 where 条件中同时校验状态和 revision,通过影响行数判断是否更新成功,避免并发覆盖。
  • 本地事务控制:本系统内部通过数据库事务保证费用扣减、结算状态更新、费用信息更新等操作的原子性。
  • 跨系统一致性控制:对于生成发药单等跨系统操作,采用补偿性事务与失败重试机制,保证最终一致性。
  • 原子扣减控制:对患者余额等扣减类资源,采用数据库原子更新语句,例如 update ... set value = value - :amt where value >= :amt,避免先查后改导致并发下出现负数或脏数据。

异常场景与优化方向

当系统在业务执行中途宕机时,本地事务内的数据能够保证一致,但跨系统调用若未执行完成,可能产生中间态数据,例如费用已扣减但发药单未成功生成。当前这种场景需要依赖业务唯一主键进行人工核对与修复。

后续可通过引入本地消息表或消息中间件,对关键事务执行过程进行落地记录,将跨系统处理改造为“本地事务落库 + 异步消息投递 + 定时补偿重试”的模式。对于长时间未完成的事务,由后台任务定期扫描并执行重试或补偿;接收方通过业务唯一标识实现幂等处理,避免重复消费导致的数据异常。

posted @ 2026-03-18 15:57  平安QAQ  阅读(19)  评论(0)    收藏  举报