Categories
程式開發

我们怎样用Go和Vue快速构建一个病患实时监控系统?


我们怎样用Go和Vue快速构建一个病患实时监控系统? 1

本文最初发布于Kasvith博客,经原作者授权由InfoQ中文站翻译并分享。

疫情爆发

2019年11月,我们听说了来自中国的第一起未知致命疾病的病例。现在,人们都知道它是Covid-19,并且它似乎永远改变了我们的生活。这种病毒是致命的,具有高度传染性。但是我们对它却知之甚少。我真心希望人类能尽快找到治愈它的方法。

我们怎样用Go和Vue快速构建一个病患实时监控系统? 2

新冠病毒

Covid-19袭击了斯里兰卡

由于这种病毒的性质,人类很难阻止它的传播。在我居住的斯里兰卡,我们面临着与其他所有人同样的处境。在这篇文章中,我们来谈谈怎样通过一些小的工作来帮助前线抗疫。

应对Covid-19病房中的风险

只要犯了很小的错误,你就可能染上致命病毒。我们的前线抗疫医护人员必须在隔离病房中来回走动,随时检查患者的生命体征。在这种任务中,医护人员接触病患后回来就要销毁一次性防护装备。但是,付出这么大的代价只为检查医疗设备上的一些读数而已。

卫生当局提出需求,希望我们能为隔离病房开发一套远程监控系统。虽然市面上针对这种监控有一些昂贵的软件,但是斯里兰卡可能没那么富裕,掏不起这么多钱。

旅途开始

因此,我们(我和Keshara)做了一些背景研究,发现这些设备通常会支持一种称为HL7(健康等级7)的通用协议,用来交换生命体征等医学数据。

我们研究了HL7协议一段时间,它看起来有点奇怪。我们从未使用过这种协议。这是一种全新的体验。

HL7消息的框架如下

我们怎样用Go和Vue快速构建一个病患实时监控系统? 3

HL7封包

在消息部分中,病患医疗数据会被打包,如下所示;是r换行符,用于分隔消息

HL7消息样本

MSH|^~&|||||||ORU^R01|103|P|2.3.1|
PID|||14140f00-7bbc-0478-11122d2d02000000||WEERASINGHE^KESHARA||19960714|M|
PV1||I|^^ICU&1&3232237756&4601&&1|||||||||||||||A|||
OBR||||Mindray Monitor|||0|
OBX||NM|52^||189.0||||||F
OBX||NM|51^||100.0||||||F
OBX||ST|2301^||2||||||F
OBX||CE|2302^Blood||0^N||||||F
OBX||CE|2303^Paced||2^||||||F
OBX||ST|2308^BedNoStr||BED-001||||||F

这是不是看起来很奇怪?我们也这么感觉。这就是所谓的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实现了这个功能。

我们怎样用Go和Vue快速构建一个病患实时监控系统? 4

Mindray uMec10

但是,当我们开始上手操作真正的设备时,它实际上没法工作。因此,我和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 %dn", len(payload))
    m, _, err := hl7.ParseMessage(payload)
    if err != nil {
        return nil, fmt.Errorf("error parsing hl7: %sn", err)
    }
    return m, err
}

系统架构

我们怎样用Go和Vue快速构建一个病患实时监控系统? 5

系统架构

我们的系统设计目标是能够长期可靠地运行。我们精心选择了适合这一任务的最佳工具。

我们选择的数据库是PostgreSQL,因为它稳定且可靠。通过HA设置,我们可以为监控系统创建一个良好可靠的数据库系统。此外,PG还支持高吞吐量数据摄取,这是一项优势。

将来再加上TimeScaleDB,我们也会将其用于实时分析。因此PG是最佳的选项,因为将来可以将TimeScale安装在它上面。

出于管理目的,我们将网关(Gateway)和API分开了。网关的设计轻巧且健壮。感谢GoLang,这是一次很棒的体验。

走向真实世界

床头监视器通过UDP协议广播它的运行状况。我们必须捕获UDP数据包并处理它们,以提取必要的细节来访问监控设备。

我们创建了一个单独的Go服务,以检测UDP广播并在系统中注册一个新设备。下一阶段是从网关连接设备内部的数据服务器。我们在Go中创建了另一个服务来处理这些TCP连接。

我们怎样用Go和Vue快速构建一个病患实时监控系统? 6

设备发现

由于网关需要作为客户端连接到设备,因此我们也必须协调客户端的连接断开。另外,我们还必须为网关中的每个监视器状态保留选项卡。

使用Go Channels,我们可以轻松地将警报保存到PostgreSQL数据库中,以供将来分析之用。

Channels能轻松实现goroutines之间无互斥的通信。它们用起来真舒服。

我之前开发一款称为Kache的Redis兼容内存数据库的经验,为我们解决许多关键问题的过程提供了很多帮助。

实时显示生命体征

我们同时开始开发一款好用的前端应用程序,以显示来自医务人员设备的实时结果。Keshara做了UI部分的重活儿,我觉得他干得很漂亮。在短短3天内,我们就完成了一个非常好的UI。

从Vuetify开始,我们开发了一种类似于床头监视器界面的自定义布局。

我们使用Vuex管理状态,并开发了基于优先级的警报服务,可在任何紧急情况下向员工发出警报。

我们还使用Socket.io连接了API和前端,这使我们能够创建一个有效的通信渠道来实时交付结果。

我必须再次感谢Keshara在UI开发过程中所做的努力。

我们怎样用Go和Vue快速构建一个病患实时监控系统? 7

实时仪表板

部署

这些设备正在以高吞吐量发送数据。我们决定为设备使用单独的VLAN,为API使用另一个VLAN,这样在处理流量时不会挤爆医院的网络。我们的大学讲师Asitha Bandaranayake博士和SunethNamal Karunarathna博士也为我们提供了帮助 。

在他们的支持下,我们建立了一个可靠的网络。接下来,我们启动了一个Ubuntu 18.04 box并开始部署系统。

Keshara在这里也做了大量繁重的工作,还要冒着感染风险在可能存在COVID患者的医院中作业。

投入生产

在下面的图片和视频中,你可以看到它的实际效果。

我们怎样用Go和Vue快速构建一个病患实时监控系统? 8

Sudarshana Wickramasinghe博士正在测试系统

我们怎样用Go和Vue快速构建一个病患实时监控系统? 9

部署完成后的Keshara和Sudarshana博士

尾声

我们应该互相帮助。我们的前线医护人员正在与病毒作战,甚至没有休息时间。我们都应该帮助他们。作为计算机工程专业的学生,​​我们开发了这套远程监控患者的系统,尽我们所能为他们提供支持。这套系统可以减少医护人员与病患的接触机会,并帮助他们提升效率和安全性。

我们感谢所有开发了出色工具/库​​的开源贡献者,没有他们的成果,这套系统也只能是一个梦想了。

使用Golang是一个绝妙的主意,我们只用了几天时间就编写了一套相当稳定的系统。

VueJS还帮助我们快速创建了高效响应的UI。

携起手来,我们就可以创造奇迹❤️

免责声明

我们应医护人员的需求创建了这款软件。它不是商业应用。即使有了这套系统,我们也强烈建议医生对患者进行实际检查。由于这款软件是在疫情爆发的背景下快速开发出来的,因此我们发布时只配备了需求最紧急的功能,也就是监控。我们对它测试了很久,同时也测试了多种设备。到目前为止,它的效果很好。

这并不表示这款软件就是完美的,我们正在努力改进并修复错误,直到它非常稳定为止。

因此,我们建议医生谨慎使用该功能。

英文原文:

How We Created a Realtime Patient Monitoring System With Go and Vue in 3 days