3. 平台总体架构设计

互联网医院平台不是把线下挂号窗口搬到网页上,而是把“患者—医生—药师—支付机构—监管平台”之间的协作关系重新组织成一套可编排、可审计、可扩展的软件系统。总体架构设计要回答三个问题:系统分成几层、每层承担什么职责;业务能力如何切分成微服务;服务之间的边界依据什么确定。本节以分层架构为骨架,以领域驱动设计(DDD)限界上下文为切分依据,给出六个核心服务的职责与调用关系。

一、分层架构:从接入到基础设施

平台采用五层结构,自上而下依次为接入层、网关层、业务服务层、领域能力层与基础设施层。分层的关键约束是“上层可调用下层,下层不得反向依赖上层”,跨层调用必须经过网关或领域能力层,避免业务逻辑散落在接入代码中。

  • 接入层:面向患者端(微信小程序、App、H5)、医生端(工作站)、药师端与运营后台,负责协议适配、页面渲染与本地缓存,不承载业务规则。
  • 网关层:统一鉴权、限流、路由、灰度与审计日志。所有外部请求先到网关,由网关完成 JWT 校验、租户识别与接口级权限判断,再转发到具体服务。
  • 业务服务层:承载用户、问诊、处方、订单、支付、消息六个核心服务,是业务编排的主体。
  • 领域能力层:沉淀可复用的领域能力,如电子签名、CA 认证、药品目录、排班引擎、计费规则、消息模板,供多个服务共享,避免重复实现。
  • 基础设施层:数据库、缓存、消息队列、对象存储、日志与监控,为上层提供持久化与异步通信能力。

分层带来的直接收益是变更可控:接入层改版不影响业务规则,领域能力升级可被多个服务同时受益,基础设施替换(如从自建 MySQL 迁移到云数据库)对业务代码透明。

二、DDD 限界上下文识别

微服务划分不能按“一张表一个服务”来切,而应按业务能力与语言边界来切。DDD 的限界上下文强调:同一个词在不同上下文里含义不同,必须显式隔离。例如“处方”在问诊上下文中是医生开具的诊疗结论,在处方上下文中是需要药师审核、具有法定效力的文书,在订单上下文中是待支付商品的一部分。三者语义不同,应分属不同上下文。

识别限界上下文的常用方法是事件风暴:先列出业务事件(如“问诊已创建”“处方已审核”“订单已支付”),再找出产生和消费这些事件的聚合与命令,最后按语言一致性和事务边界聚类。互联网医院可识别出六个核心限界上下文:用户上下文、问诊上下文、处方上下文、订单上下文、支付上下文、消息上下文。每个上下文拥有独立的数据库 schema,上下文之间只通过领域事件或防腐层(ACL)交互,禁止直接跨库联表查询。

三、核心服务职责与调用关系

六个核心服务的职责边界如下:

服务核心职责关键聚合
用户服务患者/医生/药师实名认证、档案、就诊人管理、权限与角色用户、就诊人、角色
问诊服务图文/视频问诊创建、排班匹配、会话管理、问诊状态流转问诊单、会话、排班
处方服务处方开具、药师审核、电子签名、处方状态与合规校验处方、审核记录
订单服务订单创建、费用明细、状态机、退费与对账订单、订单项
支付服务支付下单、回调处理、退款、渠道对账支付单、退款单
消息服务站内信、短信、推送、模板渲染与发送记录消息、模板

调用关系遵循“同步查询、异步通知”的原则。同步调用用于必须立即拿到结果的场景,例如问诊服务创建问诊单前需调用用户服务校验就诊人身份;异步调用用于状态变更通知,例如处方审核通过后发布“处方已审核”事件,订单服务订阅后创建订单,消息服务订阅后向患者推送通知。这样可避免服务间强耦合,也便于削峰填谷。

典型链路示例:患者发起图文问诊 → 网关鉴权 → 问诊服务校验就诊人(调用用户服务)→ 创建问诊单并匹配医生 → 医生接诊、开具处方 → 处方服务校验药品与签名 → 发布“处方已审核”事件 → 订单服务创建订单 → 支付服务完成支付 → 消息服务推送“支付成功”通知。整条链路中,问诊、处方、订单、支付各自维护自己的状态机,通过事件串联,任一环节失败均可独立重试或补偿。

四、服务间调用关系图

下图给出六个核心服务与网关、领域能力层之间的调用关系。实线表示同步调用,虚线表示基于消息队列的异步事件订阅。

互联网医院平台核心服务调用关系 API 网关(鉴权 / 限流 / 路由) 用户服务 认证 / 档案 / 就诊人 问诊服务 会话 / 排班 / 状态机 处方服务 审核 / 签名 / 合规 消息服务 短信 / 推送 订单服务 订单 / 明细 / 退费 支付服务 下单 / 回调 / 对账 领域能力层:电子签名 / CA 认证 / 药品目录 / 排班引擎 / 计费规则 / 消息模板 基础设施层:MySQL / Redis / Kafka / 对象存储 / 日志监控 同步校验 同步校验 支付 身份校验 处方已审核 订单已支付 支付结果 事件订阅 同步调用(REST / gRPC) 异步事件(Kafka 消息)

五、边界与一致性设计要点

服务划分完成后,必须明确三条工程约束。第一,每个服务独占数据库,禁止跨服务直接访问对方表;需要对方数据时通过接口或事件获取,必要时在本地建立只读投影表。第二,跨服务事务采用最终一致性:以“处方已审核”事件为例,处方服务在本地事务中写入处方状态并写入事件表,由消息中继投递到 Kafka,订单服务消费后创建订单;若消费失败则重试,超过阈值进入死信队列人工处理。第三,幂等设计:支付回调、事件消费、订单创建都必须携带业务唯一键(如处方号、支付单号),服务端据此去重,避免重复下单或重复扣款。

限界上下文不是越细越好。划分过细会导致分布式事务和网络调用激增,划分过粗则失去独立部署与弹性伸缩的意义。判断标准是:一个上下文是否由一个小团队独立负责、是否拥有独立的业务语言、是否可以独立发布而不影响其他上下文。若三个答案都是“是”,则边界基本合理。