王 信, 刘晓燕, 张开琦, 王 星, 严 馨
(昆明理工大学 信息工程与自动化学院,云南 昆明 650500)
有毒化学品的毒性和易燃易爆性,往往会影响人的健康并造成严重的经济损失,在有毒化学品运输过程中可能会发生爆炸或碰撞,因此有毒化学品的运输是极为危险的活动。一旦发生泄露事故,可能造成人员伤亡和环境污染,造成的损害是不可估量的。因此,尽可能预测、最小化有毒化学品运输事故的风险和潜在后果变得极为重要。已有一些研究人员对有毒化学品泄露扩散进行建模,预估出泄露事故的威胁区域范围。Zhang Jian-jun等[1]使用高斯烟羽模型和ArcGIS预估了有毒化学品泄露事故的威胁区域。Jakala D S[2]提出了一种基于GIS的有害化学品泄露建模工具,具有预测分析受有害化学品影响区域的功能,且可导出化学品泄露的相关数据分析报告。Cherradi G等[3]提出了一种基于微服务的实时危险材料环境信息系统。
本文通过应用基于微服务和Spring Cloud框架的针对有毒化学品运输泄漏的信息系统,可预测有毒化学品释放的有毒烟羽在意外泄露发生后的威胁范围,从而方便管理人员采取应急措施,减少有毒化学品泄漏造成的损失。上述传统的单体架构等技术解决方案模块边界模糊,不支持动态的服务发现,可扩展性不强,缺少系统故障雪崩效应、单点故障的防范和合理的资源使用配置。而本文给出的基于微服务和Spring Cloud框架的解决方案,支持服务注册发现、负载均衡、熔断保护等机制,功能模块清晰,易于动态服务部署和维护。
有毒化学品的运输活动通常与多种人员相关,如运货商、运输车、监管人员和紧急响应人员等,各方通常有不同的需求。因此,本文给出一种基于微服务的有毒化学品运输泄漏信息系统,可以提供相关人员需要获取的信息,在有毒化学品意外泄露后分析和预测有毒化学品烟羽的分散情况,以便制定有效的规划,降低在人口密集地区运输有毒化学品的风险。
本系统由多个子系统组成,包括前端(Web客户端和移动客户端)以及多个后端微服务。图1是本系统的架构示意图,图2是系统的后端微服务组成示意图。
图1 系统架构图 图2 后端微服务组成
应用程序以Docker容器的形式部署为微服务。如图2所示,后端系统由许多微服务组成,每个微服务均可以以不同的方式实现,可以具有不同的体系结构模型,并根据应用程序的性质、业务需求和优先级使用不同的编程语言和数据库。所有微服务都在Eureka注册中心进行注册,都是多实例部署。API网关作为外部请求访问后端的门户。由于各微服务都是多实例部署,故运用Ribbon组件实现负载均衡。本系统还包括熔断机制组件Hystrix,负责微服务间消息传递的Kafka分布式消息中间件。
客户端应用程序可以通过API网关与后端微服务系统进行通信,例如Web客户端发出查看运输车辆及有毒化学品信息的请求,API网关应将该请求根据定义的转发规则转发到数据采集微服务上,由于各微服务是多实例部署,根据一定的负载均衡策略和路由规则转发到合适的数据采集微服务实例上,之后通过API网关返回所需要的数据。API网关对后端微服务系统结构进行了封装并为所有客户端提供了单一入口点,同时提供了合适的API。API网关主要完成鉴权、路由、负载均衡的功能[4]。在本系统中,使用Spring Cloud框架中的Zuul网关来实现API网关的功能。
Zuul具有路由、过滤的功能,路由指将来自外界客户端的请求被Zuul网关分发到内部具体微服务中的过程;过滤则可以处理来自外界客户端的请求,以进一步实现对请求的检验和服务间的组合。若要重写自己的过滤器即定义新的过滤规则,就需要使重写的过滤器继承Zuulfilter父类,将父类的抽象方法重写[5]。对于Zuul网关,定义了4种过滤器的作用域分别为:
(1)pre:路由之前;
(2)routing:路由中;
(3)post:路由之后;
(4)error:发送错误调用。
还可使用FilterOrder定义过滤的顺序。用ShouldFilter写逻辑判断,是否要过滤;用Run写过滤器的具体逻辑。
服务的注册与发现是微服务架构中最为核心和基础的模块。如图3所示,本系统中的各个微服务都应利用服务注册中心完成服务注册和服务发现过程,采用Spring Cloud Netflix项目下的服务注册发现组件Eureka作为服务注册中心。其包含作为服务注册中心的Eureka服务端和作为一个Java客户端的Eureka客户端。在应用启动时,Eureka客户端向服务端注册自己的服务信息,同时将服务端的服务信息缓存到本地。客户端会和服务端周期性的进行心跳交互,以更新服务租约和服务信息[6]。
图3 服务注册中心功能示意
图4 Ribbon组件功能示意
由于本系统中微服务为多实例部署,故需要负载均衡组件去缓解请求的网络压力。本系统采用Spring Cloud Netflix项目下的Ribbon组件实现负载均衡功能。Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用[7]。本系统中可同时存在两种负载均衡,客户端负载均衡和服务端负载均衡。服务端负载均衡是由服务器通过配置特定的组件完成的分发工作,例如Nginx Web服务器是由Nginx完成反向代理,实现负载均衡。如Web客户端请求地理可视化微服务的数据,由Nginx完成请求的分发和负载均衡,将请求分发到合适的微服务实例之一。在客户端负载均衡中,客户端节点都有一份自己要访问的服务端清单,这些清单统统都是从Eureka服务注册中心获取的[8]。如图4所示,当地理可视化微服务需要调用数据采集微服务的数据时,地理可视化微服务作为服务消费者,借助Ribbon组件,并调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用。此时多实例部署的数据采集微服务作为服务提供者提供数据。
在本系统的后端微服务架构中,有多种且多实例部署的微服务实例,但若其中一个实例出现故障,由于各个微服务间存在紧密联系的原因,容易引发故障的连锁反应,甚至导致整体大范围的故障。因此需要避免该问题的发生,出现了诸如熔断机制等一系列的服务保护机制。本系统使用Spring Cloud Hystrix实现了断路器、线程隔离等一系列服务保护功能[9]。其中Hystrix Dashboard主要用来实时监控Hystrix的各项指标信息,可以对单个实例进行监控。通过Hystrix监测的结果,可以分析出系统运行时的问题,以便针对性地处理故障。除了可以开启单个实例的监控页面之外,还可对多个实例进行监控,监控端点/turbine.stream就是对多实例集群使用的。从端点的命名中,可以引入Turbine,通过它来汇集监控信息,并将聚合后的信息提供给Hystrix Dashboard来集中展示和监控。
各个微服务间的流处理则由作为分布式消息系统的Kafka集群来完成。在Kafka架构中,后端微服务中的大气扩散微服务、数据采集微服务、路由微服务可作为生产者,监管微服务、运输文档微服务、地理可视化微服务可作为消费者。Kafka是由Apache软件基金会开发的一个开源流处理平台[10]。该项目的目标是实现统一、高吞吐、低延迟地发送和接收大量的实时事件、日志数据。Kafka架构内部包含Topic和Broker两个组件。Topic用来对消息进行分类,每个进入到Kafka的信息都会被放到一个Topic下。Broker是用来实现数据存储的主机服务器。而由于各个Broker是互相独立部署的,故还需要一个中心服务器来进行所有Broker的管理[11]。Apache软件基金会的一个软件项目Apache ZooKeeper可提供该管理服务,可为各Broker提供配置、同步服务,命名注册等功能。每个Broker服务器在启动时,都会到ZooKeeper上进行注册。
后端微服务系统包括:
(1)数据采集微服务:数据采集微服务基于MQTT协议和Node.js开发。MQTT(Message Queuing Telemetry Transport)协议是一个基于发布/订阅范式的消息传输协议,利用broker作为消息中间件来完成多对多的客户端之间的数据传输。如图5所示,车载传感器可采集车辆信息、有毒化学品的理化性质数据、当前环境的温度、湿度、压强、风向、风速信息,利用全球定位系统(GPS)技术获取车辆实时位置,通过无线通信技术传输数据。采集到的数据将通过API网关发送给数据采集微服务中。数据采集微服务由于基于MQTT协议,故采用MQTT broker作为消息中间件,Subscriber作为客户端订阅消息。收到数据后,微服务将其存储到MongoDB数据库中。MongoDB是一个基于分布式文件存储的数据库。采集到的数据将被下文介绍的大气扩散微服务所利用。
图5 数据采集微服务
(2)地理可视化微服务:该微服务基于AngularJS、LeafletJS、GIS地图和GPS技术构建。AngularJS是一个前端JavaScript框架,协助单一网页运行。LeafletJS是用来构建在线网络电子地图的开源JavaScript库,它可以从GeoJSON文件(是一种对各种地理数据结构进行编码的格式)加载地图数据,对其进行样式设置并创建交互式图层,可以显示在地图上移动的车辆,其中包含相关重要数据和参数。此外,通过空间查询技术,它允许用户分析任何给定空间层的意义。
(3)路由微服务:该微服务基于地理信息系统(GIS)与空间数据库PostGIS、数据库管理系统PostgreSQL、PgRouting算法、Node.js构建。PostgreSQL是自由的对象-关系型数据库服务器。PostGIS是一个开源程序插件,为PostgreSQL提供了地理空间数据的支持以使PostgreSQL成为一个空间数据库[12]。基于真实城市道路数据量较大且查询分析操作步骤复杂与数据库交互频繁,服务端频繁访问数据库导致数据库开销压力较大,分析较慢,故选择PgRouting在数据库内部实现算法,提升分析效率。PgRouting是基于开源空间数据库PostGIS用于网络分析的扩展模块,最初被称作PgDijkstra,因为它只是利用Dijkstra算法实现最短路径搜索,之后慢慢添加了其他的路径分析算法。这里的路径分析不仅仅是最短路径,在实际应用中还有最短耗时、最近距离、道路对车辆类型限制、道路对速度限制等因素,交通事故、市政事故导致的交通障碍点等问题。该微服务旨在处理与道路交通网运输风险有关的地理数据,以找到使有毒化学品运输风险最小的路线。
(4)运输文档微服务:该微服务基于Alfresco、Node.js开发,为了便于多方人员(如运货商、监管人员和紧急响应人员)查看、管理有毒化学品运输活动相关文档,本文采用基于Alfresco的内容管理系统,可分类、分发、搜索、存储文档。Alfresco是一款应用最为广泛的开源的企业内容管理系统,可实现企业需要的日常的文档管理、协同工作、网络内容管理等功能[13]。对运输活动数据也可进行简单的CRUD操作,运输活动相关的数据存储在PostgreSQL中。运输文档对于公路运输有毒化学品至关重要,因此,提供适当权限的相应文档可以将事故发生率降至最低。
(5)监管微服务:由于对道路有毒化学品运输安全的监管极为重要,监管微服务基于Node.js开发,使用电子版的ADR(危险货物道路国际运输)规则,记录有毒化学品运输相关的文本数据(诸如有毒化学品分类和标识、包装和罐装规定,运输、装载、卸载的条件等),同时允许简单的CRUD操作,这些数据依然存储在PostgreSQL中。该微服务可允许系统管理人员查看有毒化学品运输监管文本数据,对关键数据的修改情况知情。通过该监管微服务,可进一步降低事故发生率。
(6)大气扩散微服务:为了对有毒化学品的泄露进行建模,给出了一种大气扩散微服务,目的是通过将大气扩散模型与GIS技术相结合来估算受到有毒化学品泄露影响的区域的大小[14]。该微服务基于Node.js开发,所产生的数据存储在MongoDB分布式数据库中。大气扩散微服务借助ALOHA软件,包含大约1000种常见危险化学品的数据库,使用该数据库中的信息,以及泄露事故地点和大气条件(温度、风速和风向等),ALOHA便可以预测释放危险气流造成的威胁范围。因此ALOHA可对有毒化学品的大气扩散进行建模。同时该微服务应与数据采集微服务和地理可视化微服务进行通信,以解决在发生泄露事故情况下实时数据的采集和有毒化学品泄露情况可视化的问题。具体而言,数据采集微服务采集到的有毒化学品运输相关数据通过Kafka消息中间件输入到大气扩散微服务中,而大气扩散微服务借助ALOHA软件可根据大气扩散模型计算出有毒化学品的烟羽威胁范围并生成KML文件(一种标记语言,利用XML语法格式描述地理空间数据),故需开发输出程序将KML格式的文件转化为GeoJSON文件(是一种对各种地理数据结构进行编码的格式),再通过Kafka消息中间件将其导入到地理可视化微服务中,以便地理可视化微服务将GeoJSON文件转化为可在网络地图上显示的有毒化学品烟羽威胁区域。
图6 Eureka服务注册中心界面
图6为服务注册中心Eureka的运行界面,微服务生态系统中的各微服务均已在Eureka中完成注册,API网关Zuul和负载均衡组件Ribbon也作为Eureka客户端注册到Eureka Server下。
作为API网关的Zuul具有服务路由、负载均衡、服务过滤功能,在系统部署运行之前配置调用地址,外部请求就可以根据所定义的规则来访问微服务实例。如下代码所示,可在application.yml中定义路由规则,凡是/data/**的访问都转发到数据采集微服务上,凡是/geo/**的访问都转发到地理可视化微服务上。
zuul:
routes:
api-a:
path:/data/**
serviceId:data-collection
api-b:
path:/geo/**
serviceId:geo-visualization
API网关Zuul通过服务过滤的功能,可以实现安全验证,让客户端只访问特定的资源,从而保护系统的安全性。通过继承ZuulFilter抽象类,实现其自定义的4个抽象函数,即可自定义过滤器:
(1)filterType:返回过滤器类型;
(2)filterOrder:过滤器的使用顺序;
(3)shouldFilter:布尔型,控制是否使用过滤器;
(4)run:实现过滤器的具体逻辑。
在本系统中Zuul网关过滤器的具体实现代码如下:
@Override
public Object run(){
RequestContext ctx=RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
Object accessToken = request.getParameter(s:"access token");
if(accessToken == null){
log.warn("access token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
return null;
}
Log.info("access token ok");
Return null;
}
图7 网格表示的威胁区域
在大气扩散微服务中,开发输入程序用于将数据采集微服务采集到的有毒化学品和气象条件等数据传递给大气扩散微服务中的ALOHA软件。输入程序要与ALOHA通信,需要调用NERegister()来使用NOAA_32.dll注册输入应用程序[15],通过发送“REGA”消息(注册应用程序),通知ALOHA:外部应用程序已准备好与之进行数据通信。然后,我们的输入应用程序使用描述我们需求的字符串,调用NESendMessage()来发送消息,通过调用NEGetNextMessage()来接收消息,通过调用NEBye()取消注册应用程序。使用此通信方式,输入程序从数据提供者采集微服务数据并将其传输给ALOHA。然后ALOHA处理这些数据以创建有毒化学品的烟羽模型[16],将其输入到输出程序中,将ALOHA所产生的KML文件转换为GeoJSON文件并导入地理可视化微服务。如图7所示,在ALOHA中可将计算出的威胁区域用网格的形式表示出来,分别以不同的颜色(图形)代表不同的区域中有害烟羽的浓度。此时的各项数据如泄漏时间、地点、有毒化学品及运输载体信息、泄漏地点气象条件数据等如图8所示。
图8 有毒化学品运输相关数据
在网络地图上显示有毒化学品烟羽威胁区域有助于决策者估计有毒烟羽在人口密集区域的扩散情况,以便紧急响应人员确定疏散措施。因此,使用地理可视化微服务来绘制ALOHA所估算出威胁区的范围。一旦将GeoJSON数据导入地理可视化微服务,就可以进行分析和决策,从而保护公共基础设施和居民的安全。开发输出程序以辅助完成这一过程。为将KML文件转换为GeoJSON格式的数据文件,要在基于Node.js构建的输出应用程序中使用Togeojson库。Togeojson库将KML格式的文件转换为GeoJSON格式的文件。第一个参数必需是作为XML DOM格式的KML文件,输出是作为JavaScript对象的GeoJSON文件,GeoJSON文件可以直接在利用Leaflet.js构建的地理可视化微服务中使用,以在网络地图上呈现出有毒化学品烟羽的威胁区域。如图9所示,可以在Google地图上以可视化的形式绘制出有毒化学品泄露的威胁区域,不同的区域颜色深浅代表不同的污染物浓度水准。
图9 地图上显示危险气体的扩散情况
本文给出了一种基于微服务的有毒化学品运输泄漏信息系统,采用Spring Cloud框架下的服务注册中心、API网关、负载均衡、熔断保护及分布式消息中间件Kafka等组件来保障整个系统的高效、平稳运行。相比传统单体架构等技术解决方案的复杂、不易维护和部署的特点,该系统支持服务的注册发现机制,可动态部署,可扩展性强,对系统故障有更好的防范,资源得到更合理的利用。同时,各微服务被部署在Docker容器中,提高了运维的效率。本系统预测了有毒化学品在道路运输意外泄露后的受威胁区域,可以帮助决策人员采取有效的措施来降低事故后果,避免不必要的经济和环境损失。未来进一步的研究工作着眼于对更加精确预测有害化学品大气扩散建模方法的选择,并优化系统的响应时间,以更加及时地得到分析预测的结果。