1. 为什么说WEB架构是电子病历系统的必然选择
真正上手做过医疗信息化项目的人,都绕不开一个核心系统:电子病历(EMR)。前些年很多医院还在用C/S架构的老病历系统,客户端装在医生工作站上,每次升级都要逐台机器去更新,部门之间的数据还经常不同步。后来行业整体转向WEB电子病历,不是说换个浏览器访问就叫WEB化,而是从部署方式、交互模式、数据流转到维护链路整个重做了一遍。现在你打开浏览器,输入医院内网的地址,就能完成从患者建档、书写病程、开立医嘱到提交病案的完整流程,这才是WEB电子病历该有的样子。
这套系统能解决什么问题?最直观的是把病历从“写在纸上的记录”变成“能在浏览器里实时读写和流转的临床数据资产”。医生不用再等检验结果打印出来才知道数值,护士在病区录入的体温单、血糖值,医生端几秒内就能看到。对信息科来说,WEB架构最大的价值是“一份代码,全院内网都能跑”,不用再维护几百台客户端的运行环境。对医院管理者来说,病历数据集中存储在服务器端,做质控、统计、科研检索都变得高效。
这篇内容适合谁看?如果你是正在做医疗信息化项目的开发人员、准备从零搭建电子病历系统的架构师,或者想把自己医院的病历系统从C/S迁移到WEB的技术负责人,这篇东西能给你省不少踩坑的时间。我不会只讲概念,会把设计思路、表结构、接口逻辑、部署细节和排障经验全部拆开来说。
2. 整体设计与选型思路拆解
2.1 为什么选B/S架构而不是继续用C/S
先说一个常识:B/S架构的本质是把业务逻辑全部收敛到服务器端,浏览器只负责渲染和交互。电子病历这个场景对部署一致性要求极高,因为临床科室的电脑配置参差不齐,有十年前的老机器也有新配的国产终端,如果做C/S客户端,光是兼容不同操作系统、不同显卡、不同办公软件环境就能让人崩溃。用WEB之后,只要机器能跑浏览器,系统就能用,兼容性问题大幅减少。
另外还有升级成本。按照卫健委对电子病历分级评价的要求,系统需要不断迭代功能,比如新增过敏史结构化的录入、增加护理计划模块、调整病历模板。WEB架构下,重启一下后端服务或者让前端重新构建部署,全院终端下一次刷新页面就是新版本,不需要逐台机器去装补丁。这一点在落地时节省的时间成本是实打实的。
有人会担心浏览器的复杂表格编辑能力。早期确实有这个问题,一个病历文书里动辄几十个字段,还有签名、打印、续打等需求。但在现在的技术条件下,用富文本编辑器加上自研的表格控件,配合打印样式控制,体验已经可以做到和原生桌面应用很接近。我见过不少团队在这个点上纠结太久,其实不如先跑通一个完整流程再慢慢优化。
2.2 前后端分离还是服务端渲染
这是做WEB电子病历必须回答的问题。市面上很多老牌厂商用的是服务端渲染方案,后端用JSP或者模板引擎直接出页面,好处是SEO友好,但这玩意儿对电子病历来说意义不大,毕竟系统在内网跑,不需要搜索引擎收录。坏处反而明显:前后端代码耦合严重,改一个输入框的样式往往要动到后端的Java或者Python代码,联调效率低。
我推荐前后端分离方案。前端用Vue或React做单页应用,后端只提供纯粹的RESTful API或JSON-RPC接口。电子病历的场景里有大量的状态流转、弹窗确认、异步校验,前端的交互复杂度非常高,分离架构可以让前端团队专注做交互体验,后端团队专注做业务逻辑和数据库操作。
具体的分工是:
- 前端仓库:负责登录页、工作台、病历文书编辑器、医嘱录入界面、模板管理界面等
- 后端服务:负责患者索引、病历文档存储、医嘱处理、权限校验、签名验证、质控规则引擎等
- 数据库层:MySQL或PostgreSQL存业务数据,Redis存会话和缓存,Elasticsearch可以做病历全文检索
前端构建后用Nginx托管静态文件,反向代理到后端接口。后端接口统一走HTTPS协议,内网虽然不一定需要公网证书,但至少要用自签证书保证传输加密,防止局域网内的明文嗅探。
2.3 关键模块怎么划分
一套完整可用的WEB电子病历,至少要包含以下模块:
- 患者主索引:统一管理患者的身份信息、住院号、门诊号、历次就诊记录
- 病历文书:门急诊病历、住院病历、病程记录、手术记录、护理记录、知情同意书等
- 医嘱管理:长期医嘱、临时医嘱的录入、审核、执行、停止、作废
- 模板与知识库:病种模板、常用词库、临床路径,让医生不需要从零打字
- 质控管理:时限质控、完整性质控、合理性质控,比如“入院记录必须在入院后24小时内完成”这种规则
- 电子签名:与CA对接,实现医护人员的身份认证和操作防抵赖
- 打印与PDF输出:病历文书要能按标准格式打印,要能归档成PDF存证
- 检索与统计:支持按诊断、按医生、按时间范围检索病历,用于科研和报表
核心流程是医生登录系统后进入工作台,选择患者,系统自动带出患者基本信息,医生根据病程阶段选择对应的病历模板,填写完成后提交,系统做必填项校验,进入质控环节,最后归档。所有操作都会被审计,谁在什么时间改了哪个字段都有记录。
设计的时候最忌讳贪大求全。我见过有团队一上来就想做AI辅助诊断、知识图谱、自动编码,结果主流程都没跑通。正确的做法是先做医疗文书的“增删改查签”,把数据模型稳定下来,再逐步叠加能力。
3. 核心实现:数据模型与接口设计
3.1 病历文档的数据结构怎么设计
电子病历不像普通的表单数据,一份门诊病历可能只有几个字段,但一份住院大病历有现病史、既往史、个人史、家族史、体格检查、辅助检查、初步诊断、治疗意见等等,字段是树形的,而且不同科室的侧重点完全不同。所以,数据模型不能做成统一的宽表,否则会有几十上百个字段,大部分是空的,维护起来非常痛苦。
实践中推荐混合方案:
- 结构化索引字段:患者ID、就诊ID、文书类型、填写医生ID、记录时间、最后修改时间、状态等,放在关系型数据库的表里,方便查询和统计
- 非结构化文档内容:把整个文书的表单数据序列化为JSON存入一个文档字段,或者直接存MongoDB。这样做的好处是模板灵活,新增一个科室字段不用改表结构
以PostgreSQL为例,可以直接用JSONB类型。又想要关系型查询能力,又想要文档型灵活性,JSONB是电子病历场景下的很好的折中。需要快速检索的时候,对JSONB字段建立GIN索引,对索引字段建立普通索引。
一个简化版本的表结构是这样:
CREATE TABLE emr_document ( id BIGSERIAL PRIMARY KEY, patient_id VARCHAR(32) NOT NULL, encounter_id VARCHAR(32) NOT NULL, doc_type_code VARCHAR(32) NOT NULL, doc_status SMALLINT NOT NULL DEFAULT 0, content JSONB NOT NULL, created_by VARCHAR(32) NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_by VARCHAR(32), updated_at TIMESTAMPTZ, submitted_at TIMESTAMPTZ, signed_at TIMESTAMPTZ, deleted_flag SMALLINT NOT NULL DEFAULT 0 ); CREATE INDEX idx_emr_doc_patient ON emr_document(patient_id); CREATE INDEX idx_emr_doc_encounter ON emr_document(encounter_id); CREATE INDEX idx_emr_doc_type ON emr_document(doc_type_code); CREATE INDEX idx_emr_doc_status ON emr_document(doc_status); CREATE INDEX idx_emr_doc_created ON emr_document(created_at);字段先别急着定死,等运行一段时间再根据实际查询需求做优化。我这里特意用了deleted_flag做逻辑删除,因为病历是医疗文书,物理删除会引出合规和审计问题,哪怕是误操作,也必须走“作废”流程而不是直接删除数据。
3.2 一个核心接口的设计示例
病历保存接口是写入频率最高的接口,也是最容易出问题的接口。很多新手在设计时直接把前端表单的JSON原样POST到后端,后端也不做校验就存库。一旦前端被篡改或者保存了脏数据,整个病历就废了。
我的方案是前后端都校验,前端做交互提示,后端做强制校验。以保存一份病程记录为例,后端接口会做三层校验:
# 伪代码示例,实际项目里用FastAPI/Flask都可以实现 def save_progress_note(payload): # 第一层:基础参数校验 if not payload.get("patient_id") or not payload.get("encounter_id"): raise BizException("缺少患者或就诊信息") if not payload.get("content"): raise BizException("病历内容不能为空") # 第二层:文书状态校验,防止覆盖已提交的记录 doc = get_document(payload["id"]) if payload.get("id") else None if doc and doc.status >= DOC_STATUS.SUBMITTED: raise BizException("该文书已提交,不允许直接修改") # 第三层:业务规则校验 required_fields = get_template_required_fields(payload["doc_type_code"]) missing = [field for field in required_fields if not payload["content"].get(field)] if missing: raise BizException(f"缺少必填项: {', '.join(missing)}") doc_id = save_document(payload) add_audit_log(user_id, action="SAVE_PROGRESS_NOTE", doc_id=doc_id) return {"doc_id": doc_id}需要注意,电子病历的“保存”有两个层次。一个是草稿保存,医生写着写着先存起来,方便下次继续编辑;另一个是提交保存,表示这份病历已经完成,进入质控流程。提交流程需要做更严格的校验,而且一旦提交,医生再想修改就必须走“申请修改—上级审批—修改留痕”的路径,设计时一定要把这个状态机理清楚。
3.3 权限与审计:医疗数据的高压线
医疗数据不同于普通业务数据,它的敏感程度非常高。WEB电子病历系统在权限设计上至少要落实以下几层:
- 数据范围权限:医生只能看自己负责的患者的病历,护士只能看自己病区的患者
- 功能权限:住院医生能写医嘱但未必能开停某些特殊药物,护士能执行医嘱但不能修改医嘱内容
- 字段级权限:部分敏感信息(如HIV检测结果、精神科诊断)需要对非相关医护人员做脱敏处理
- 操作审计:每次查看、修改、打印、导出都要记录操作日志
权限模型可以用经典的RBAC(基于角色的访问控制),再结合数据归属校验。特别需要提醒的是,无论前端怎么隐藏按钮,后端接口都必须做二次鉴权。很多电子病历安全事故不是系统被外部攻破,而是内部人员越权访问,或者测试接口没有关闭,被人用Postman直接调用。
审计日志我建议单独建表,不要和业务日志混在一起。字段至少要包含操作人、操作时间、操作类型、目标对象、IP/MAC地址、操作前后的数据快照(或摘要)。用数据快照的成本较高,但遇到医疗纠纷时,这是最有力的举证材料。我在实际项目里会把修改前的JSON快照压缩之后存到独立的审计归档表,不影响主流程的性能。
4. 部署实战:从开发到内网上线的完整过程
4.1 Nginx反向代理与前后端联调配置
很多团队用Nginx只是做静态文件托管,其实在WEB电子病历项目里,Nginx承担的职责要重得多:HTTPS终结、反向代理、静态资源缓存、请求体大小限制、超时控制。下面是我在项目中验证过的一套核心配置(不涉及敏感内容,仅做技术参考):
server { listen 443 ssl; server_name emr.hospital.internal; ssl_certificate /etc/nginx/certs/emr.crt; ssl_certificate_key /etc/nginx/certs/emr.key; # 前端静态资源 root /data/emr-frontend/dist; index index.html; # 单页应用路由处理 location / { try_files $uri $uri/ /index.html; } # 后端API代理 location /api/ { proxy_pass http://127.0.0.1:8000/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 病历文书的请求体可能比较大,必须调大限制 client_max_body_size 20m; # 病历保存是耗时操作,要保证超时时间足够 proxy_connect_timeout 60s; proxy_read_timeout 120s; } # 静态资源缓存 location ~* \.(js|css|png|jpg|svg|woff2)$ { expires 7d; add_header Cache-Control "public, immutable"; } }一个比较容易踩的坑是client_max_body_size。默认只有1MB,如果病历文书里嵌入了大量的base64图片(有些医院要求在病历中插入患者照片、检查图片),请求体很容易超过1MB,然后前端就报“413 Request Entity Too Large”,但医生不知道是Nginx拦截的,只会觉得系统坏了。我建议在配置里明确调大,同时从产品上引导用户尽量上传压缩后的图片。
4.2 后端服务的环境配置与启动
后端服务我优先推荐使用FastAPI或者Flask,配合SQLAlchemy操作数据库。FastAPI自带OpenAPI文档,调试接口非常方便,而且异步性能好,可以配合数据库连接池扛住早高峰的并发访问。
下面是一份虚拟环境下的依赖清单和启动方式:
# 创建虚拟环境 python3 -m venv venv source venv/bin/activate # 安装依赖(按需增减) pip install fastapi uvicorn sqlalchemy psycopg2-binary redis pydantic pydantic-settings # 启动服务,监听内网地址 uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4--workers 4的意思是开4个worker进程,具体数值要看服务器的CPU核心数,一般取CPU核数的1到2倍。如果数据库查询写得不高效,开再多的worker也是白搭,反而会因为进程间抢占连接池把数据库拖垮。所以,接口性能优化重点要放在SQL语句的索引命中和减少不必要的N+1查询上。
实际使用中还建议用systemd托管后端进程,避免终端退出后服务也跟着退出。一个简化的systemd服务文件如下:
[Unit] Description=EMR Backend Service After=network.target postgresql.service redis.service [Service] User=emr Group=emr WorkingDirectory=/data/emr-backend ExecStart=/data/emr-backend/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4 Restart=always RestartSec=5 Environment="PYTHONUNBUFFERED=1" [Install] WantedBy=multi-user.target用Restart=always可以保证后端进程意外崩溃时自动拉起。医院信息科通常不会时刻盯着服务器,自动重启机制是救命的底线。
4.3 一份可复用的部署检查清单
三年的时间里我反复用一张清单来检查部署是否到位,每次帮医院上线或迁移系统都能派上用场:
- 服务器时钟是否同步:病历记录时间必须统一,用NTP同步到同一时间源
- 数据库备份是否配置:至少每日全量备份加实时WAL归档,备份要定期演练恢复
- HTTPS证书是否有效:自签证书要安排在每一台接入终端上安装信任根证书
- 会话超时时间是否合理:医生写病历可能会长时间挂机,超时时间太短会丢内容,太长又不安全,我一般设置为30分钟无操作后弹窗提醒、60分钟后强制重新登录
- 病毒软件是否添加白名单:有些医院终端装了安全软件,可能会拦截前端JS的缓存写入,导致页面加载异常
- 同一内网下的其他系统是否冲突:特别是80/443端口,如果医院内网已经有OA或LIS系统占用了端口,Nginx配置里就要用其他端口
电子病历上线当天,我建议信息科和技术支持团队提前准备好一张应急联系电话表,并且安排人员在重点科室(急诊科、内科病区、外科病区)现场蹲点,处理医生在使用中的即时反馈。系统上线初期,医生的抵抗情绪是最重的,现场有人能解答问题,可以大大降低上线阻力。
4.4 浏览器兼容性与服务器资源估算
WEB电子病历对浏览器环境的依赖比较大。医院内网的终端浏览器五花八门,有IE内核的、Chrome、Edge、国产浏览器,还有各种安全浏览器。我在项目中会明确要求使用基于Chromium内核的浏览器版本,并在登录页做自动检测,如果检测到低版本或不兼容的浏览器,提示用户下载指定的浏览器版本。
资源估算方面,一个500张床位的二级医院,日常同时在线的医生和护士大约150到200人,高峰期(早上查房后集中开医嘱)可能到300人。按这个规模,后端服务器配置8核16G内存就够用,数据库单独一台物理机或虚机,4核8G开始起步。如果条件允许,把前端静态资源放到CDN或者独立的Nginx上,虽然是在内网,也能减轻单台服务器的压力。
5. 落地实战中的难点:从Web页面到一份合规的病历
5.1 病历文书编辑器:为什么不能直接用现成富文本
这是整个系统里技术含量最高、也是最能看出团队功力的部分。普通的富文本编辑器(比如常见的CKEditor、TinyMCE)拿来写文章没问题,但病历文书有两个特殊要求:一是“结构化”,二是“不可随意更改”。
“结构化”是说病历的每个段落应该是独立的元素,比如主诉、现病史、既往史、体格检查,每个段落既要有文本内容,还要有字段标识,这样后期做质控、统计、科研检索的时候才能按字段抽取数据。如果全都混在一个HTML大字符串里,后期想提取“所有高血压患者的既往史描述”就麻烦了。
所以,我的方案是基于Slate.js或ProseMirror这类底层编辑器框架,自己封装一套病历块编辑器。每个块(Block)对应一种类型的病历内容——普通段落、结构化字段、表格、签名区域等。保存的时候把这些块序列化成JSON,而不是纯HTML。渲染的时候再根据JSON渲染成适合打印的版式。这个开发量不小,但当你看到医生用结构化模板一键生成格式规范的入院记录时,会觉得一切都值得。
“不可随意更改”不是说不能让医生修改,而是说编辑过程中要保留痕迹。我的方案是:草稿状态可以自由改,提交后进入留痕状态,任何修改都生成一条变更记录,新旧版本对比一目了然。要实现版本对比,最简单的办法是用类似diff算法比较两次JSON的差异,然后把差异点渲染给质控人员看。
5.2 打印与PDF导出:隐藏的大坑
电子病历最终是要打印归档的。很多团队在屏幕上调试得很完美,一打印就乱,行间距不对、页边距变了、分页把表格劈成两半。这个问题我在项目里处理了很长时间,总结下来核心就三件事:
- 打印样式独立编写,用
@media print控制,打印时隐藏按钮、导航栏,强制用A4纸型 - 表格和块级元素设置
break-inside: avoid,防止跨页断裂 - 打印字体统一使用中文字体集(宋体、仿宋、黑体按需设置),同时确保服务器或终端安装了对应字体
PDF导出建议用无头浏览器方案,比如Puppeteer加载前端页面然后生成PDF。这样导出的PDF和屏幕显示、打印出的效果完全一致,避免了另写一套渲染模板还要保持两边同步的坑。生成PDF的接口独立出来,放在后端定时任务里执行,医生点击“打印”后,系统异步生成好PDF推送到前端,避免请求等待太久。
5.3 病案归档与质控规则
病历写完了不意味着流程结束。按管理要求,出院病历要在规定时间内完成归档。系统里要有归档模块,病历主索引关联所有住院期间的文书、医嘱、检验检查报告,归档时做一次全量完整性检查,缺哪份文书就提示哪份。
质控规则我会拆成“硬质控”和“软质控”。硬质控比如“入院记录在入院后24小时内完成”“抢救记录在抢救后6小时内完成”,这是红线,规则不满足直接拦截提交。软质控比如“主诉少于20个字”“现病史里有疑似复制粘贴的字段”,规则不满足只提示,不阻断,以免影响医生的工作效率。
这里有一个经验:质控规则要尽量做到可配置。不要每次改规则都发版,把规则存到数据库表里,后台管理员可以自己增删改,规则引擎在提交时读取生效的规则并执行。我们当时是把规则做成了JSON格式的声明式配置,类似{"field": "admission_time", "max_hours": 24},提高了迭代效率。
6. 安全防线与常见问题排查实录
6.1 WEB电子病历的安全防护重点
医疗系统是网络攻击的重点目标,等保测评也单独对医疗行业有严格要求。WEB电子病历在安全建设上至少要做这几件事:
- 身份认证:对密码强度做限制,开启登录失败锁定策略,防止暴力破解
- 访问控制:所有接口都要校验JWT或会话,禁止未登录访问;重要操作要二次验证PIN码
- 传输加密:全站HTTPS,不允许HTTP明文回退
- 输入校验:后端必须对每个参数做类型、长度、格式校验,防止SQL注入和XSS攻击
- 数据防泄漏:病历数据导出要审批留痕,后台管理员账号要绑定操作人真实身份,禁止共用维护账号
另外还建议在Nginx层加基础的防护策略,比如限制单IP的请求速率、禁止通过IP直接访问后端端口、隐藏后端服务的版本信息。这些操作虽然简单,但能挡住大量自动化的扫描探测。具体到代码里,SQL操作一定要用参数化查询,不要用字符串拼接。前端渲染医生填写的内容时要转义HTML,避免存储型XSS——想象一下,医生在病历里填了一个<script>标签,所有打开这份病历的电脑都执行了恶意脚本,这个场景是很恐怖的。
6.2 高频故障排查技巧
我在落地过程中遇到了大量问题,整理出下面几个最常遇到的,可以作为排查手册来参考:
问题1:页面能打开但接口请求一直转圈
- 排查思路:先看浏览器F12里的Network请求,看接口返回的状态码。如果是404,大概率是Nginx的
proxy_pass路径配错了,/api/反代到后端时前缀是否被正确剥离;如果是504,后端服务可能挂了或者超时,检查后端进程是否存活、数据库连接是否正常
- 排查思路:先看浏览器F12里的Network请求,看接口返回的状态码。如果是404,大概率是Nginx的
问题2:医生反馈“保存成功”但重新打开内容丢失
- 排查思路:检查前端保存时是否真的调用成功接口。很多次是前端在表单校验失败时拦截了请求,但页面提示语写得不够明确,让医生以为保存成功了。建议在前端明确区分“草稿保存中”“已保存”“保存失败”三种状态,用不同颜色标识
问题3:同一时间大量人员登录,系统响应很慢
- 排查思路:这种通常是数据库连接池被打满,或者接口存在慢查询。先看后端日志里的SQL执行时间,重点排查病历列表查询、患者检索这类高频接口的索引使用情况。必要时对高频查询增加Redis缓存
问题4:其他科室系统通过API调用电子病历的数据,偶尔超时
- 排查思路:外部系统调用内部接口时,一定要设置合理的超时时间,而且调用方要加熔断机制。曾出现过LIS系统批量同步检验结果时,一次性把上千条数据POST过来,后端又没有限制请求体大小,直接把服务拖垮的案例。建议所有对接接口统一使用消息队列做异步削峰
问题5:系统提示“Web视图加载错误”
- 排查思路:如果医生用的是定制浏览器或老旧终端,可能是浏览器内核版本过低,无法支持现代JavaScript语法。解决办法是在构建前端时设置
browserslist兼容目标,把ES6代码转译到ES5,同时滚动升级终端浏览器版本
- 排查思路:如果医生用的是定制浏览器或老旧终端,可能是浏览器内核版本过低,无法支持现代JavaScript语法。解决办法是在构建前端时设置
6.3 浏览器兼容矩阵
这里有必要单独拿一个小节来说,因为医疗内网的终端环境真的比公网复杂得多。我在项目中维护了一张兼容性矩阵,每次前端发布前会按这个表格过一遍:
| 浏览器环境 | 兼容级别 | 说明 |
|---|---|---|
| Chrome 90+ / Edge 90+ | 完全支持 | 开发主目标,推荐医生使用 |
| 国产浏览器(Chromium内核) | 完全支持 | 只要内核版本在90以上,基本无问题 |
| Firefox 最新版 | 基本支持 | 偶有打印样式微调,需要回归测试 |
| IE11 | 不支持 | 已停止适配,登录页做拦截提示 |
| 移动端浏览器(PAD) | 部分支持 | 可用于查看病历,不建议书写复杂文书 |
做兼容的时候,最大的坑是“医生说自己的浏览器是最新版”,实际上打开的是系统自带的旧版IE兼容模式外壳。所以登录页要显示浏览器内核版本号,信息科远程指导时一眼就能判断问题所在。
7. 一些实战后的心得体会
做WEB电子病历这个方向,踩过的坑比做过的功能还多。如果让我给刚入行的团队一句建议,我会说:先跑通最核心的“医生写一份病历并完成提交”这个闭环,再谈其他的加分功能。很多厂商在宣传时把界面做得花团锦簇,但实际部署后医生最常用的功能就是开单和书写病程,这些地方不流畅,其他都是空中楼阁。
病历数据的结构化程度决定了系统的上限。从数据建模的第一天起,就要把“这份数据将来要用于检索和统计分析”这个念头刻在脑子里。我见过不少病历系统,半年后想统计“全院糖尿病患者使用二甲双胍的比例”,结果发现诊断和用药信息都以大段文本形式躺在数据库里,根本无法准确统计,只能人工翻阅纸质病历,这完全是设计阶段的失误。
在部署层面,再啰嗦一句:上线前一定要做流量演练。别看医院内网不像互联网有几十万并发,但早交班后那半小时的集中开医嘱请求,以及出院的集中打印请求,很容易让没有经过压测的服务直接挂掉。至少用压测工具模拟200个用户同时保存病历,观察后端接口的响应时间,超过3秒就不要强行上线。
最后分享一个小经验:系统上线后不要急着加新功能,先用一个月时间把使用中暴露出来的性能和易用性问题修复完。医疗系统的连续性比什么都重要,一个稳定运行的基础版本,远比一堆华而不实的功能更有价值。