影像云平台影像处理架构优化实战

/ 2评 / 31

背景

影像云平台是将医院传统胶片替换为数字影像云胶片,患者将不需要打印传统胶片,扫码二维码可查看到数字影像。
云平台的最为核心重点就是DICOM数字影像【DICOM简介 】,数字影像的来源是由医院PACS系统提供,一个CT影像检查可简单理解为有几百至几千张影像,每张影像大小为几百KB至40/50MB。
此次架构优化是基于【影像云平台提升高可用性实战简述】(建议先阅读) 后的第二次较大架构重构优化,影像云平台影像处理项目是私有云独立部署在医院,限制较多的技术栈的使用。

目标

影像处理项目高可用提升至4个9。
不丢失一张DICOM数字影像数据。

识别复杂度

业务复杂度:与医院PACS系统 和 Hospital front-end processor C++ 进行深度整合。
项目背景复杂度:5年多持续升级旧项目、原核心技术人员已离职、无可追溯的技术架构设计文档。
环境复杂度:私有云独立部署、不可访问外网、局域网也存在诸多限制。
数据复杂度:一个CT影像检查可简单理解为有几百至几千张影像,每张影像大小为几百KB至40/50MB,一次CT影像检查至少几百MB至1/2G。

原有架构分析

原逻辑架构简化示意图

这张原来逻辑架构简化图,医院PACS系统实时将DICOM影像推送至 Hospital front-end processor C++,经过处理后,将DICOM影像推送至影像处理Java项目,影像处理Java项目是私有云独立部署的微服务,服务之间的通信采用的端对端异步gRPC通信方式,每个服务分别会做接收、转换、压缩、归档等等处理。
此架构方式虽简单易用,但存在天然的数据不可靠的情况,DICOM影像数据大上传时占用链接过长,极易导致连接超时。当下游服务超过规定时间不可用的时,无再次自动重试导致丢失或需人工进行重发DICOM影像。

架构优化方案

演进中的逻辑架构简化图

上图演进中的逻辑架构简化图,根据服务业务逻辑处理性质进行再次业务领域的调整,为了项目解耦更彻底,去gRPC化引入消息队列,服务通信采用消息队列进行传递。
当原来的点对点调用方式变更为RabbitMQ消息队列方式时,我们也必须要面临消息队列同样的问题需要处理。

为什么选择RabbitMQ

目前Google上有太多的消息队列中间的对比文章,这里也不做搬运工,更详细的对比建议Google。
而对于我们选择RabbitMQ的原因,主要是考虑是开源社区成熟度、产品中已有别的项目在使用RabbitMQ,因影像处理服务是单个医院私有云部署方式,性能并非我们考虑的第一重点。

影像消息顺序一致性

首先需要识别影像业务处理中是否存在需保证消息顺序一致性的问题,在流程处理上我们需要做到服务A执行完后,服务B开始执行、服务C开始执行,服务……,我们通过控制发送消息队列通知的下个服务环节,当下个服务环节收到可执行的策略后,则会开始执行。所以影像业务处理中的业务流程是可以保证一致的。
其次每个CT检查都有很多张影像,那么这样影像应该如何保证顺序?否则医生看阅片时会出现第一张看的肺部,下一张变到腹部影像。 而解决这个问题,对于DICOM影像而言有天然的优势,在DICOM影像里有个tag是标记影像在每个影像序列的顺序。

DICOM Tag

最后,结合DICOM影像的特性的,只要保证业务服务流程的顺序,消息顺序一致性的可以妥善解决。

影像消息重复

首先还是需要结合业务背景,先判断影像传输在不使用消息队列的情况,我们是否也会面临重复的问题?答案是肯定是的,一个检查存在很多影像,在正常情况如果患者手工上次影像文件时,如果部分上传失败,患者也是全部再上传一遍而不是挑选漏掉上传的那部分。
所以既然影像处理本来就要支持消息幂等性,只要我们每次都正确消费影像消息就可以,同个影像是update也不是insert。

影像文件传输

在原有架构中,虽然在内网环境中,但每次影像大文件传输都会给服务长时间占用链接,从而导致传输超大文件时容易造成连接数过多。
通过改造在第一个微服务环节时,将影像临时存储本地硬盘中,通过Nginx提供对外下载服务,其他服务在需要时可自行下载影像文件,在所有微服务处理完毕后,自动将影像文件删除。
这样的方式不仅节约内网带宽的占用,也节约了原来发送影像文件所带来的Java服务的性能损耗。

影像消息可靠性和持久化

影像消息可靠性最终目前是保证患者影像检查的影像数量一张不少。
实际上在医院环境中,内网环境也不是我们认为的可靠性很高,除非技术上故障外,还存在人为的一些网络调整,当出现这些问题后,我们首先要保证的消息是否正确发送到RabbitMQ上,消费者是否有正确将消息进行消费,当RabbitMQ重启后消息还未并消费完的消息应该怎么办?
我们综合考虑性能的原因,我们选择RabbitMQ确认机制 + 非持久化 + 业务ACK + 自动影像校对机制。
关于选择消息非持久化的原因:

应对消息堆积方案

调整队列消息设置过期时间TTL,原来没有设置过期导致堆积过多,也导致了新的影像推送过来后都存在较长处理时间的滞后性。
当队列消息超过存活时间后,有专门的服务处理死信交换机的消息,根据是否成功处理的结果再进行下一步的通知。
消息堆积的处理方案我认为还是要站在业务角度上去考虑,最为重要的堆积的消息是否可接受丢失,是否需要及时正确消费掉,这个将决定消息堆积处理方案的难易度。

RabbitMQ高可用

RabbitMQ部署方式,主要有三种:单机模式、普通集群模式、镜像集群模式。
单机模式目前只是应用在我们开发及内网测试环境上。
普通集群模式,本质上并非真正高可用,只是提升了吞吐量,暂不适用我们。
镜像集群模式,确保了每个MQ实例都存在完整的镜像,任何节点宕机都不受影响,虽然有性能开销较大,但综合计算单医院部署和内网带宽而言,经过RabbitMQ Performance Testing Tools测试性能几乎不受太大的变动。

RabbitMQ监控

因医院网络环境特殊不可访问外网,自建监控中间件如发现异常也无法通知给运维人员。
目前我们对于RabbitMQ的Logging、Tracing、Metrics、Healthchecks的监控,主要是采用多种混合的方式,在部署起初主要看RabbitMQ自身的Log,部署后我们较常使用RabbitMq Management 、 Firehose插件、Prometheus(被动观察)、院内现有健康检测系统。

总结

架构设计需要结合团队及业务实际情况,没有最好的架构方案,只有当下最适合的架构方案,不能将原来公司或大厂的经验直接照搬,否则当初设定的目标无法解决,还会引入更多其他问题。
在此次引入RabbitMQ并没有采用RabbitMQ所有特性,尽量将RabbitMQ变轻,减少医院私有云运维上的工作。

  1. GTZ说道:

    请问图用什么画的?

发表评论

您的电子邮箱地址不会被公开。