本文最初发布于 Kasvith 博客,经原作者授权由 InfoQ 中文站翻译分享。
现创建了一个“程序员从业者聚集圈”圈内会不定时更新Android、Java等进阶资料;也会分析相对应的从业环境和经验分享;当然也欢迎大家吐槽吹牛;进圈方式放在了文末
疫情爆发
2019 年 11 月,我们听说了来自中国的第一起未知致命疾病的病例。现在,人们都知道它是 Covid-19,并且它似乎永远改变了我们的生活。这种病毒是致命的,具有高度传染性。但是我们对它却知之甚少。我真心希望人类能尽快找到治愈它的方法。
imageCovid-19 袭击了斯里兰卡
由于这种病毒的性质,人类很难阻止它的传播。在我居住的斯里兰卡,我们面临着与其他所有人同样的处境。在这篇文章中,我们来谈谈怎样通过一些小的工作来帮助前线抗疫。
应对 Covid-19 病房中的风险
只要犯了很小的错误,你就可能染上致命病毒。我们的前线抗疫医护人员必须在隔离病房中来回走动,随时检查患者的生命体征。在这种任务中,医护人员接触病患后回来就要销毁一次性防护装备。但是,付出这么大的代价只为检查医疗设备上的一些读数而已。
卫生当局提出需求,希望我们能为隔离病房开发一套远程监控系统。虽然市面上针对这种监控有一些昂贵的软件,但是斯里兰卡可能没那么富裕,掏不起这么多钱。
旅途开始
因此,我们(我和 Keshara)做了一些背景研究,发现这些设备通常会支持一种称为 HL7(健康等级 7)的通用协议,用来交换生命体征等医学数据。
我们研究了 HL7 协议一段时间,它看起来有点奇怪。我们从未使用过这种协议。这是一种全新的体验。
HL7 消息的框架如下
image.png在消息部分中,病患医疗数据会被打包,如下所示;是\r换行符,用于分隔消息
HL7 消息样本
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 语言
Go 或 Golang 是一种静态类型的语言,其语法是从 C 语言中宽松地派生的,具有诸如垃圾收集(就像 Java)、类型安全性和某些动态类型功能等特性。这种语言由一群聪明的开发人员,包括 Robert Griesemer、Rob Pike 和 Ken Thompson 于 2007 年在谷歌开发。
Go 是为并发而构建的,它在语言中将并发视为“一等公民”来提供支持。Go 具有 goroutines 和 Channels,可让程序员以最少的投入快速开发高度并发的程序。
因此,我们决定选择 Golang。对于这项任务来说,我们认为需要处理很多并发任务。另外,Go 二进制文件是静态构建的,因此可以轻松在医院的系统上安装软件,而无需添加其他依赖项。
我们一直在寻找用 Go 编写的优秀的库,并发现了这款库写得很好。同时,其作者也撰写了一篇关于 HL7 的精彩博客文章。
它支持轻松选择和解析消息。
为什么选择 VueJS
Vue 是用于构建用户界面的渐进式框架。与其他单体框架不同,Vue 是完全从头设计为支持渐进采用的。
在 VueJS 中,我们可以轻松地创建漂亮的响应式 UI。你也知道它非常出色、简单而强大,所以我们选择了它。我们还用 Vuetify 作为 UI 库。
我们得到一部设备
读过Mindray 床头监视器的程序员指南后(这种设备在医院中很常见,因此我们选择了它),我们制作了一个小的程序原型来解码 hl7 消息。它可以正确解码 hl7 消息并将数据正确转换为 JSON。我们使用程序员手册中定义的 Unsolisticated Result Interface 实现了这个功能。
image但是,当我们开始上手操作真正的设备时,它实际上没法工作。因此,我和 Keshara 开始在 Wireshark 中分析数据包,来检查设备实际上是在做什么。结果,我们发现它根本不是在使用这个协议。它使用的是 Realtime Result Interface,这是一种很老的接口,制造商已经不再维护它。
从 HL7 中提取一条消息
从设备中提取 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
}
系统架构
image我们的系统设计目标是能够长期可靠地运行。我们精心选择了适合这一任务的最佳工具。
我们选择的数据库是 PostgreSQL,因为它稳定且可靠。通过 HA 设置,我们可以为监控系统创建一个良好可靠的数据库系统。此外,PG 还支持高吞吐量数据摄取,这是一项优势。
将来再加上 TimeScaleDB,我们也会将其用于实时分析。因此 PG 是最佳的选项,因为将来可以将 TimeScale 安装在它上面。
出于管理目的,我们将网关(Gateway)和 API 分开了。网关的设计轻巧且健壮。感谢 GoLang,这是一次很棒的体验。
走向真实世界
床头监视器通过 UDP 协议广播它的运行状况。我们必须捕获 UDP 数据包并处理它们,以提取必要的细节来访问监控设备。
我们创建了一个单独的 Go 服务,以检测 UDP 广播并在系统中注册一个新设备。下一阶段是从网关连接设备内部的数据服务器。我们在 Go 中创建了另一个服务来处理这些 TCP 连接。
image.png由于网关需要作为客户端连接到设备,因此我们也必须协调客户端的连接断开。另外,我们还必须为网关中的每个监视器状态保留选项卡。
使用Go Channels,我们可以轻松地将警报保存到 PostgreSQL 数据库中,以供将来分析之用。
Channels 能轻松实现 goroutines 之间无互斥的通信。它们用起来真舒服。
我之前开发一款称为Kache 的 Redis 兼容内存数据库的经验,为我们解决许多关键问题的过程提供了很多帮助。
实时显示生命体征
我们同时开始开发一款好用的前端应用程序,以显示来自医务人员设备的实时结果。Keshara 做了 UI 部分的重活儿,我觉得他干得很漂亮。在短短 3 天内,我们就完成了一个非常好的 UI。
从 Vuetify 开始,我们开发了一种类似于床头监视器界面的自定义布局。
我们使用 Vuex 管理状态,并开发了基于优先级的警报服务,可在任何紧急情况下向员工发出警报。
我们还使用 Socket.io 连接了 API 和前端,这使我们能够创建一个有效的通信渠道来实时交付结果。
我必须再次感谢 Keshara 在 UI 开发过程中所做的努力。
image部 署
这些设备正在以高吞吐量发送数据。我们决定为设备使用单独的 VLAN,为 API 使用另一个 VLAN,这样在处理流量时不会挤爆医院的网络。我们的大学讲师 Asitha Bandaranayake 博士和 SunethNamal Karunarathna 博士也为我们提供了帮助 。
在他们的支持下,我们建立了一个可靠的网络。接下来,我们启动了一个 Ubuntu 18.04 box 并开始部署系统。
Keshara 在这里也做了大量繁重的工作,还要冒着感染风险在可能存在 COVID 患者的医院中作业。
投入生产
在下面的图片和视频中,你可以看到它的实际效果。
image image尾 声
我们应该互相帮助。我们的前线医护人员正在与病毒作战,甚至没有休息时间。我们都应该帮助他们。作为计算机工程专业的学生,我们开发了这套远程监控患者的系统,尽我们所能为他们提供支持。这套系统可以减少医护人员与病患的接触机会,并帮助他们提升效率和安全性。
我们感谢所有开发了出色工具 / 库的开源贡献者,没有他们的成果,这套系统也只能是一个梦想了。
使用 Golang 是一个绝妙的主意,我们只用了几天时间就编写了一套相当稳定的系统。
VueJS 还帮助我们快速创建了高效响应的 UI。
携起手来,我们就可以创造奇迹❤️
免责声明
我们应医护人员的需求创建了这款软件。它不是商业应用。即使有了这套系统,我们也强烈建议医生对患者进行实际检查。由于这款软件是在疫情爆发的背景下快速开发出来的,因此我们发布时只配备了需求最紧急的功能,也就是监控。我们对它测试了很久,同时也测试了多种设备。到目前为止,它的效果很好。
这并不表示这款软件就是完美的,我们正在努力改进并修复错误,直到它非常稳定为止。
因此,我们建议医生谨慎使用该功能。
https://shimo.im/docs/vJCgvwgrhXxJCTDG/ 《程序员从业者聚集地》,可复制链接后用石墨文档 App 或小程序打开
网友评论