2020年5月,我所在公司为某一线城市开发《云智慧医疗决策管理系统》,该系统通过云平台技术, 形成针对整个城市中不同机构、 角色和业务活动的智能化应用,实现患者与医务人员、医疗机构、医疗设备之间的互动, 包括任意查询、 即兴分析、 业务增强、 规则约束、 预测未来、 发现知识, 并提供互动性、 及时性、 预知性、 洞察性, 从而达到实现智慧医疗的目 标。在项目中,我是系统架构师的角色,负责该系统的架构设计工作。
本文根据智慧医疗的具体应用场景结合云原生的设计原则,来阐述云原生架构在该项目中的具体 应用,该系统采用SpringCloud框架开发,系统总的分为云设施基础层、业务层、展现层三部分,其中云基础设施包含分布式存储、分布式计算、数据挖掘算法等等基础设施的资源;业务层我们将其划分为多个微服务,我们采用Docker云容器来部署服务,使用Kubernetes来实现容器的编排,使用Eureka来实现服务的治理;展现层采用前后端分离的思想,责数据处理后的展现。系统于年底发布V1.0版本,在优先满足医疗机构急需的传染病辅助决策等功能的同时,我们根据需求继续完善系统的功能。
近年来云计算平台不断的发展和完善,基础设施即服务(IaaS)、平台即服务(PaaS)、软件即服务(SaaS),随着大数据基础设施的完善,又出现了数据即服务(DaaS)的环境,以后随着智能化的发展还会有和其相关的基础设施。云原生的架构就是基于云计算平台进行的软件架构设计,以便做到资源的共享和重用。云原生的架构设计原则主要有服务化原则、弹性原则、可观测性、韧性原则、所有过程自动化原则、零信任原则、架构持续演进原则等等,后面分别阐述在我们项目基础设施搭建的初期所用到的原则。
2020年5月,我所在公司为某一线城市开发《云智慧医疗决策管理系统》,该系统采用SpringCloud框架开发,系统总的分为云设施基础层、业务层、展现层三部分。下面针对这三层展开具体的说明。
一、云基础设施层
医疗机构每天产生大量的数据,这些数据主要来源于医疗业务活动、 健康体检、 公共卫生等 9 项医疗卫生服务。 数据内容包括来自医院的大量电子病历、 区域卫生信息平台采集的居民健康档案等。 其中大量充斥着非结构化/半结构化的数据, 包括图像, office 文档, 以及 XML 结构文档等。 智慧医疗云平台的应用, 关键是整合所有可能得到的这些数据, 这就需要我们建立云基础设施。基础设施的建设主要包括两大部分,一是大数据采集和存储,二是诸如数据挖掘算法之类的计算资源。
由于我们团队目前规模小,所以在云基础设施建设方面分两步走,对于医疗机构急需的如通过大数据对疾病发展趋势进行决策分析;通过大数据为患者医疗提供辅助的决策分析之类的功能,我们采取Serverless的方案,该云原生架构屏蔽了服务器的各种运维复杂度,无需为资源使用提前进行容量规划,使我们在前期的成本得到有效的降低,让我们的开发人员可以将更多精力用于业务逻辑设计与实现。
第二就是我们搭建自己的基础设施。由于Serverless这种架构模式缺乏自主控制权,还有重要的就是长时间运行流程的高成本,我们有很多业务逻辑的进程需要持续运行很长时间,所以我们需要运行自己的服务器,我们的云基础设施搭建主要用到的技术有Docker云容器+ Kubernetes+ SpringCloud,以下涉及到的基础设施建设均指自己的。
二、服务支撑层
服务支撑平台是一个长期化的工作。在平台服务支撑建立的初期,我们使用Docker进行容器搭建;使用Kubernetes进行容器编排管理;使用SpringCloud实现服务管理、服务框架、注册发现、服务治理、调用链、日志管理、流量监控等功能,来逐渐搭建自己的云基础设施。
三、数据层
数据层作为底层的一个核心层,我们将其分为数据采集、数据预处理、数据存储三部分。
1、数据采集:我们系统的数据来源医院、社区卫生、公共卫生机构等信息系统、日志、设备。其中以关系型数据库和日志的来源居多。目前初期阶段数据采集主要以Kettle为主,因为kettle可以从关系型数据库和日志中轻易的分离出我们需要的特征。
2、数据预处理:我们系统预处理主要完成对已接收数据的清洗预处理和转换预处理, 转换已处理目 的是将数据按统一的格式提取出来,可以帮助我们将这些复杂的数据转化为单一的或者便于处理的构型, 以达到快速分析处理的目 的,初期我们对于关系型数据库采用的主要是Kettle工具; 清洗预处理包括缺失值处理、异常值处理、重复值处理等,我们采用MapReduce来处理日志数据,采用kettle来处理关系型数据库的数据。
3、数据存储:对采集来的数据进行存储,前期我们采用HDFS来存储来自日志的数据,使用MongoDB来存储来自关系关系型数据库和其它来源的数据。
四、业务层
在项目中我们要完成医院、社区卫生、公共卫生机构、卫生综合管理等等 业务的数字化与智能化建设,我们将业务拆分为微服务,每个服务基于Docker单独开发、运行、测试,服务启动后使用Eureka将自身信息注册到注册中心,通过REST API实现服务间的通信。对于访问非常频繁的服务,我们将其部署为多个示例,使用Ribbon实现这些实例的负载均衡问题。
在云原生架构中,我们往往将一个大的业务子系统拆分为很多独立运行的微小的服务,以便于独立开发、独立测试、独立运维、独立演变,服务之间的修改需不影响。那么问题来了,在原来单体架构中,一个业务子系统可以独立运行来完成某种特定的业务功能,那么这些服务如何协同工作完成某一特定的业务功能呢?这里给出几种参考的方案,请读者按照自己实际的业务场景来决策。
1、服务之间直接通信
例如在《医疗急救一体化管理子系统》中的急救信息管理服务、计算机急救受理、社区特别服务、地理信息服务等等,采用服务之间直接通信的集成方式,这种方式缺点是造成复杂的调用关系,不利于管控,所以不是很特别的类似急救系统这样的服务功能,我们很少采取这种调用关系。
2、通过API网关来集成
通过API网关来集成服务的好处是可以对服务的调用进行集中的管控,这种方式是项目中比较常见的选择,如下图所示。
3、通过服务的编排来实现
通过服务的编排来实现服务间的相互调用来形成新的业务能力,供客户端调用,如下图所示。
4、通过消息中间件来实现服务间的调用
采用消息中间件机制的系统中,不同的对象之间通过传递消息来激活对方的事件,完成相应的操作。发送者将消息发送给消息服务器,消息服务器将消息存放在若干队列中,在合适的时候再将消息转发给接收者。通过消息中间件来实现服务间的调用这种方式比较适合服务关系简单且明确的应用场景,也是分布式事务处理的一个手段。如下图所示。
五、接入层
接入层包括数据展现、服务网关、负载均衡三部分。
数据展现实现数据在手机端APP、电脑端浏览器等设备的数据展现,我们采用前后端分离的策略,使用REST API和后端进行通信;
使用Nginx实现负载均衡。当用户通过网络访问我们系统的时候,负载均衡服务器会将请求通过Nginx集群通过http协议和后端通信,来起到对用户请求进行分流的作用。
初期阶段我们通过服务网关实现对外服务集成管控;服务网关只负责服务路由,并不参与数据通信。
在云原生的实践过程中,我们遇到了一些问题,一是分布式事务的问题,我们采用二阶段提交协议和基于消息的最终一致性方案来解决;二是服务划分不合理,由于医疗领域业务流程非常复杂,后续我们将和相关领域专家多交流,建立以领域为驱动的业务模型,好在我们的各层结构合理,把业务层升级为领域层无需过多的修改现有的服务;三是运维开销及成本增加,以后还可能加入Go语言和python语言的生态圈,这将对我们现有技术是个挑战,所有自己的云平台建设是一个循序渐进的过程,不可急功近利。再有就是负载均衡我们采用的是HTTP重定向的方式,虽然实现起来比较简单,但是性能较差,后期随着我们技术力量的不断增强,我们将采取反向代理等机制来实现负载均衡。