本文最初发布于Kasvith博客,经原作者授权由InfoQ中文站翻译并分享。
2019年11月,我们听说了来自中国的第一起未知致命疾病的病例。现在,人们都知道它是Covid-19,并且它似乎永远改变了我们的生活。这种病毒是致命的,具有高度传染性。但是我们对它却知之甚少。我真心希望人类能尽快找到治愈它的方法。
新冠病毒
由于这种病毒的性质,人类很难阻止它的传播。在我居住的斯里兰卡,我们面临着与其他所有人同样的处境。在这篇文章中,我们来谈谈怎样通过一些小的工作来帮助前线抗疫。
只要犯了很小的错误,你就可能染上致命病毒。我们的前线抗疫医护人员必须在隔离病房中来回走动,随时检查患者的生命体征。在这种任务中,医护人员接触病患后回来就要销毁一次性防护装备。但是,付出这么大的代价只为检查医疗设备上的一些读数而已。
卫生当局提出需求,希望我们能为隔离病房开发一套远程监控系统。虽然市面上针对这种监控有一些昂贵的软件,但是斯里兰卡可能没那么富裕,掏不起这么多钱。
因此,我们(我和Keshara)做了一些背景研究,发现这些设备通常会支持一种称为HL7(健康等级7)的通用协议,用来交换生命体征等医学数据。
我们研究了HL7协议一段时间,它看起来有点奇怪。我们从未使用过这种协议。这是一种全新的体验。
HL7消息的框架如下
HL7封包
在消息部分中,病患医疗数据会被打包,如下所示;是\r
换行符,用于分隔消息
MSH|^~\&|||||||ORU^R01|103|P|2.3.1|<CR>
PID|||14140f00-7bbc-0478-11122d2d02000000||WEERASINGHE^KESHARA||19960714|M|<CR>
PV1||I|^^ICU&1&3232237756&4601&&1|||||||||||||||A|||<CR>
OBR||||Mindray Monitor|||0|<CR>
OBX||NM|52^||189.0||||||F<CR>
OBX||NM|51^||100.0||||||F<CR>
OBX||ST|2301^||2||||||F<CR>
OBX||CE|2302^Blood||0^N||||||F<CR>
OBX||CE|2303^Paced||2^||||||F<CR>
OBX||ST|2308^BedNoStr||BED-001||||||F<CR>
这是不是看起来很奇怪?我们也这么感觉。这就是所谓的Pipehat格式,它使用|
来分隔各段。我在这里不会深入讨论这种协议,你可以在互联网上找到大量相关资源。我们发现了一些很酷的库,它们用不同的语言编写来处理HL7消息。
Go或Golang是一种静态类型的语言,其语法是从C语言中宽松地派生的,具有诸如垃圾收集(就像Java)、类型安全性和某些动态类型功能等特性。这种语言由一群聪明的开发人员,包括Robert Griesemer、Rob Pike和Ken Thompson于2007年在谷歌开发。
Go是为并发而构建的,它在语言中将并发视为“一等公民”来提供支持。Go具有goroutines和Channels,可让程序员以最少的投入快速开发高度并发的程序。
因此,我们决定选择Golang。对于这项任务来说,我们认为需要处理很多并发任务。另外,Go二进制文件是静态构建的,因此可以轻松在医院的系统上安装软件,而无需添加其他依赖项。
我们一直在寻找用Go编写的优秀的库,并发现了这款库写得很好。同时,其作者也撰写了一篇关于HL7的精彩博客文章。
它支持轻松选择和解析消息。
Vue是用于构建用户界面的渐进式框架。与其他单体框架不同,Vue是完全从头设计为支持渐进采用的。
在VueJS中,我们可以轻松地创建漂亮的响应式UI。你也知道它非常出色、简单而强大,所以我们选择了它。我们还用Vuetify作为UI库。
读过Mindray床头监视器的程序员指南后(这种设备在医院中很常见,因此我们选择了它),我们制作了一个小的程序原型来解码hl7消息。它可以正确解码hl7消息并将数据正确转换为JSON。我们使用程序员手册中定义的Unsolisticated Result Interface实现了这个功能。
Mindray uMec10
但是,当我们开始上手操作真正的设备时,它实际上没法工作。因此,我和Keshara开始在Wireshark中分析数据包,来检查设备实际上是在做什么。结果,我们发现它根本不是在使用这个协议。它使用的是Realtime Result Interface,这是一种很老的接口,制造商已经不再维护它。
从设备中提取HL7消息的过程如下。我们使用了bufio.Reader
,因为它有一个处理输入流的有效方法。有了Reader
,我们就无需每次都访问网络层,而是能够有效地从底层TCP连接中读取数据。
func (d *Device) ProcessHL7Packet() (hl7.Message, error) {
// read message start 0x0B
b, err := d.ReadByte()
if err != nil {
return nil, fmt.Errorf("error reading start byte: %s", err)
}
if b != byte(0x0B) {
return nil, fmt.Errorf("invalid header")
}
// read payload
payloadWithDelimiter, err := d.ReadBytes(byte(0x1C))
if err != nil {
return nil, fmt.Errorf("error reading payload: %s", err)
}
// just verify and process next byte on the line
b, err = d.ReadByte()
if err != nil {
return nil, fmt.Errorf("error reading end byte %s", err)
}
if b != byte(0x0D) {
return nil, fmt.Errorf("invalid message end")
}
// skip last two bytes from the hl7 packet
payload := payloadWithDelimiter[:len(payloadWithDelimiter)-1]
log.Debugf("Length of payload %d\n", len(payload))
m, _, err := hl7.ParseMessage(payload)
if err != nil {
return nil, fmt.Errorf("error parsing hl7: %s\n", err)
}
return m, err
}
系统架构
我们的系统设计目标是能够长期可靠地运行。我们精心选择了适合这一任务的最佳工具。
我们选择的数据库是PostgreSQL,因为它稳定且可靠。通过HA设置,我们可以为监控系统创建一个良好可靠的数据库系统。此外,PG还支持高吞吐量数据摄取,这是一项优势。
将来再加上TimeScaleDB,我们也会将其用于实时分析。因此PG是最佳的选项,因为将来可以将TimeScale安装在它上面。
出于管理目的,我们将网关(Gateway)和API分开了。网关的设计轻巧且健壮。感谢GoLang,这是一次很棒的体验。
床头监视器通过UDP协议广播它的运行状况。我们必须捕获UDP数据包并处理它们,以提取必要的细节来访问监控设备。
我们创建了一个单独的Go服务,以检测UDP广播并在系统中注册一个新设备。下一阶段是从网关连接设备内部的数据服务器。我们在Go中创建了另一个服务来处理这些TCP连接。
设备发现
由于网关需要作为客户端连接到设备,因此我们也必须协调客户端的连接断开。另外,我们还必须为网关中的每个监视器状态保留选项卡。
使用Go Channels,我们可以轻松地将警报保存到PostgreSQL数据库中,以供将来分析之用。
Channels能轻松实现goroutines之间无互斥的通信。它们用起来真舒服。
我之前开发一款称为Kache的Redis兼容内存数据库的经验,为我们解决许多关键问题的过程提供了很多帮助。
我们同时开始开发一款好用的前端应用程序,以显示来自医务人员设备的实时结果。Keshara做了UI部分的重活儿,我觉得他干得很漂亮。在短短3天内,我们就完成了一个非常好的UI。
从Vuetify开始,我们开发了一种类似于床头监视器界面的自定义布局。
我们使用Vuex管理状态,并开发了基于优先级的警报服务,可在任何紧急情况下向员工发出警报。
我们还使用Socket.io连接了API和前端,这使我们能够创建一个有效的通信渠道来实时交付结果。
我必须再次感谢Keshara在UI开发过程中所做的努力。
实时仪表板
这些设备正在以高吞吐量发送数据。我们决定为设备使用单独的VLAN,为API使用另一个VLAN,这样在处理流量时不会挤爆医院的网络。我们的大学讲师Asitha Bandaranayake博士和SunethNamal Karunarathna博士也为我们提供了帮助 。
在他们的支持下,我们建立了一个可靠的网络。接下来,我们启动了一个Ubuntu 18.04 box并开始部署系统。
Keshara在这里也做了大量繁重的工作,还要冒着感染风险在可能存在COVID患者的医院中作业。
在下面的图片和视频中,你可以看到它的实际效果。
Sudarshana Wickramasinghe博士正在测试系统
部署完成后的Keshara和Sudarshana博士
我们应该互相帮助。我们的前线医护人员正在与病毒作战,甚至没有休息时间。我们都应该帮助他们。作为计算机工程专业的学生,我们开发了这套远程监控患者的系统,尽我们所能为他们提供支持。这套系统可以减少医护人员与病患的接触机会,并帮助他们提升效率和安全性。
我们感谢所有开发了出色工具/库的开源贡献者,没有他们的成果,这套系统也只能是一个梦想了。
使用Golang是一个绝妙的主意,我们只用了几天时间就编写了一套相当稳定的系统。
VueJS还帮助我们快速创建了高效响应的UI。
携起手来,我们就可以创造奇迹❤️
我们应医护人员的需求创建了这款软件。它不是商业应用。即使有了这套系统,我们也强烈建议医生对患者进行实际检查。由于这款软件是在疫情爆发的背景下快速开发出来的,因此我们发布时只配备了需求最紧急的功能,也就是监控。我们对它测试了很久,同时也测试了多种设备。到目前为止,它的效果很好。
这并不表示这款软件就是完美的,我们正在努力改进并修复错误,直到它非常稳定为止。
因此,我们建议医生谨慎使用该功能。
英文原文:
How We Created a Realtime Patient Monitoring System With Go and Vue in 3 days
领取专属 10元无门槛券
私享最新 技术干货