2. ELN系统总体架构设计

ELN(电子实验记录系统)的总体架构设计,决定了系统能否在合规审计、高并发写入、多实验室协同和长期演进之间取得平衡。本节从分层架构入手,对比微服务与单体架构的取舍,再落到前后端分离、API 网关和服务注册发现这几个关键机制,并给出系统上下文图与容器图的绘制方法。

一、分层架构:把职责切清楚

ELN 的典型分层自下而上为:基础设施层(数据库、对象存储、消息队列、缓存)、数据访问层(ORM、仓储 Repository)、领域服务层(实验记录、签名、审计、权限等业务规则)、应用/接口层(REST/gRPC 接口、DTO 转换、事务边界)、表现层(Web 前端、移动端、第三方集成)。

分层的核心约束是依赖单向向下:表现层只能调用接口层,接口层调用领域服务,领域服务通过仓储访问数据,任何一层不得反向依赖。这样做的直接收益是:审计规则(如“记录一旦签名不可修改”)集中在领域服务层,前端改版或新增移动端时不会触碰合规逻辑。

一个常见的错误是把业务规则写进 Controller 或直接写 SQL 到前端。ELN 涉及 GxP 合规,签名、时间戳、版本链一旦散落在多层,审计追踪就无法保证完整性。因此建议在领域服务层显式定义不可变记录与追加式审计日志两个核心抽象。

二、微服务与单体架构对比

ELN 早期版本通常从单体起步,因为团队小、领域边界尚未稳定。单体架构的优点是事务简单(一个数据库事务即可保证记录与审计日志一致)、部署单一、调试方便;缺点是模块耦合后,签名服务的高安全要求会被迫与普通查询一起发布,扩容也只能整体扩容。

微服务架构把实验记录、签名与审计、用户与权限、文件存储、通知等拆成独立服务。它的优势是:签名服务可以独立加固与审计、文件服务可独立扩容、不同团队并行开发。代价是分布式事务、跨服务一致性、链路追踪和运维复杂度显著上升。

对 ELN 这类系统,较务实的路线是模块化单体起步,按合规边界拆分。判断是否拆分的依据不是“服务越小越好”,而是:该模块是否有独立的合规要求、是否有明显不同的伸缩特征、是否由不同团队长期维护。签名与审计通常是最先被拆出的服务,因为它对可用性、密钥管理和审计隔离的要求与普通 CRUD 差异最大。

三、前后端分离与 API 网关

前后端分离指前端只通过 HTTP/JSON 与后端交互,不嵌入服务端模板。ELN 前端通常是单页应用(SPA),负责实验记录编辑、富文本、附件上传、签名确认等交互;后端只提供无状态 API。这样前端可独立发布,后端可独立扩容,也便于未来接入移动端或第三方 LIMS。

API 网关位于客户端与后端服务之间,承担统一入口职责:路由转发、JWT 鉴权、限流、请求日志、协议转换(外部 REST 转内部 gRPC)、灰度发布。对 ELN 而言,网关还是审计入口——所有写操作经过网关时记录操作者、时间、来源 IP 和请求摘要,形成审计追踪的第一段证据。

下面这张容器图展示了 ELN 的主要容器、数据流向与网关、注册中心的位置关系:

实验人员 Web / 移动端 QA / 审计员 只读审计视图 LIMS / 仪器 数据导入接口 前端 SPA 记录编辑 / 签名确认 附件上传 / 审计查询 API 网关 路由 / JWT 鉴权 限流 / 审计入口 服务注册与发现 Consul / Nacos / Eureka 后端微服务集群 实验记录服务 记录 CRUD / 版本链 签名与审计服务 电子签名 / 审计追踪 用户与权限服务 RBAC / 组织架构 文件存储服务 附件 / 对象存储 通知服务 邮件 / 站内消息 数据存储层 PostgreSQL / Redis / MinIO HTTPS 路由转发 服务注册 服务发现 用户请求 服务调用 注册/发现

四、服务注册发现:让调用方找到实例

微服务实例的 IP 和端口是动态的(容器重建、扩缩容都会变化),因此需要注册中心。服务启动时向注册中心注册自身地址与健康状态,调用方通过服务名查询可用实例列表,再由客户端或网关做负载均衡。

以 Nacos 为例,实验记录服务启动时执行注册,配置片段如下:

spring:
  application:
    name: eln-record-service
  cloud:
    nacos:
      discovery:
        server-addr: 10.20.30.40:8848
        namespace: eln-prod
        group: ELN_GROUP
        metadata:
          version: v1.3.0
          zone: lab-a

注册成功后,可在 Nacos 控制台看到实例列表,健康检查默认采用心跳机制(临时实例 5 秒心跳,15 秒未收到标记不健康,30 秒剔除)。调用方通过 http://eln-record-service/api/records 这样的服务名访问,由 Ribbon 或 Spring Cloud LoadBalancer 解析为具体实例。

需要特别注意的是健康检查与合规的关系:签名服务若被误判为不健康而剔除,可能导致签名请求失败。因此签名服务建议配置为持久实例(非临时实例),并配合主动健康检查,避免因网络抖动导致服务被摘除。

五、系统上下文图与容器图的绘制要点

系统上下文图(Context Diagram)只画 ELN 系统与外部角色/系统的关系,不展开内部结构。ELN 的外部对象通常包括:实验人员、QA 审计员、LIMS、仪器数据采集系统、企业 SSO、邮件/通知网关。每条连线标注交互内容与协议,例如“实验人员 → ELN:提交记录,HTTPS/JSON”。

容器图(Container Diagram)展开到可独立部署的单元:前端 SPA、API 网关、各微服务、数据库、缓存、对象存储、消息队列。容器图不展开到类或函数,但应标注每个容器的技术选型与职责。上文 SVG 即是一张典型的 ELN 容器图,读者可对照它检查自己的设计是否遗漏了注册中心、审计入口或文件存储。

绘制容器图时,建议先列出所有“可独立部署单元”,再补充它们之间的同步调用(实线)与异步消息(虚线)。ELN 中记录写入与审计日志写入建议采用同步事务保证一致性,而通知、报表生成等可采用异步消息,降低主链路延迟。
微服务拆分不是目标。若团队不足 10 人、领域边界尚未稳定,强行拆分会导致分布式事务、链路追踪和运维成本远超收益。ELN 的合规边界(签名、审计)是少数值得优先拆分的模块,其余可先在模块化单体中保持清晰包边界。

综上,ELN 总体架构的设计顺序建议为:先确定分层与依赖方向,再判断哪些模块需要独立部署,然后确定前后端分离与网关职责,最后引入注册发现解决动态寻址。系统上下文图回答“系统与谁交互”,容器图回答“系统由哪些可部署单元组成、如何连接”,两者配合即可在编码前把架构讲清楚。