[关闭]
@lxx3061313 2017-04-28T08:23:15.000000Z 字数 8569 阅读 193

Mossad-本木医疗智能终端治理服务

背景

  1. Mossad is the national intelligence agency of Israel. It is one of the main entities in the Israeli Intelligence Community, along with Aman (military intelligence) and Shin Bet (internal security). Mossad is responsible for intelligence collection, covert operations, and counterterrorism, as well as bringing Jews to Israel from countries where official Aliyah agencies are forbidden, and protecting Jewish communities. Its director reports directly to the Prime Minister.

随着公司业务的发展,在整个北京地区部署的远程设备越来越多,随之暴露出来的问题也越来越多,概括来讲主要是围绕设备的维护管理工作。
ModulesOfMachine.jpg-25.6kB
设备的核心模块如上图所示,数据入口有读卡器,扫描器。数据出口有打印机。中间模块有验证模块和银联支付模块。任何一个模块出现故障都会影响整体流程,从而导致设备不可用。而在一个模块内部可能涉及到的流程最多可达十几个之多。所以在没有可靠及时的数据收集系统和数据清洗系统之前,要想高效率的维护这些设备几乎不可能。
除此之外,设备正常运行所需的元数据管理混乱,设备自身软件模块的升级维护管理落后低效,设备故障处理缺乏流程化标准化等问题随着设备数量的增多开始成为公司的绊脚石。在这种背景下,一套高效的,可靠的管理系统急需建立。
下面我来详细分析下远程设备管理涉及的几个方面工作。

分析

远程设备作为一个智能体,在固定目标区域提供相关的智能服务。对它的管理工作主要涉及以下方面:

元数据管理

元数据指的是远程设备正常启动并提供服务所需要的非业务基础数据。这个比较好理解,类似于操作系统的BIOS信息. BIOS信息是如此的重要,以至于计算机必须在最开始就找到它。这是因为BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性等等。在此之后,计算机心里就有谱了,知道应该去读取哪个硬件设备了。远程设备也一样,因为通常它会依赖除自身之外的第三方信息来完成业务流程,所以在启动阶段需要验证一些服务是否处于正常状态,比如银联模块需要连接银联服务进行签到,卡管模块需要验证可用性。
metadata.jpg-29.5kB
如上图所示,元数据集中管理,持久化到DB的同事同步缓存在REDIS中。这样不仅解决了元数据管理混乱的问题,访问性能也得到保证。

设备远程控制管理

远程控制的使用对象主要是运维人员。一个高效的,功能健全的远程控制系统可以极大的提高运维人员的运维效率,从而降低公司的运营成本。
image_1benhcrit1qc5apr1tcoqd21spc3c.png-39.6kB
从上图可以看出,设备的远程控制主要分为两种。一种是命令式远程控制;一种是可视化远程控制。
命令式远程控制是自动化任务的基础。在运维工作中,为了提高效率,一般都会把独立的任务封装成自动化任务。这样既可以提高操作的可靠性和高效性,也可以降低运维的成本。而命令式远程控制的核心在于建立设备与后端服务的通信方式。详细内容将在下面"基于MQTT协议的数据收集系统"小节进行介绍。

可视化远程控制,相比于命令式远程控制虽然复杂,但是通过开源工具VNC (Virtual Network Console)来实现并没有多少难度。

程序自动升级管理

典型的升级系统主要包括一下步骤:
updateStep.jpg-19.2kB
当然,一个完善的升级系统远不止这么粗略,比如升级包部分需要有版本管理。传输部分需要有网络控制模块,限流模块,高效传输模块等。升级部分需要考虑跨版本升级,回滚等功能。限于篇幅,本文只详细介绍远程传输模块,详细内容请查看"基于P2P的文件传输系统"小节的内容。

异常实时监控报警系统

设备的运维管理主要基于设备的故障状态。因此及时准确的获取设备的故障状态是运维工作的基础。
monitorSystem.jpg-40.3kB
上面的结构图展示了一个监控系统所需要的大致流程。监控的及时性由设备上报异常的及时性来保证。监控的有效性和准确性由数据收集系统的清洗和分类功能来保证。最后"干净"的数据持久化到存储设备。报警系统和展示系统从持久化设备获取数据通过渲染来显示成人类易读的图表,并且这些数据经过报警系统计算后适时的通过消息平台通知到相关负责人。
渲染和报警通知已有成熟的系统来完成。所以核心的过程在于数据的收集。而数据收集的核心在于设备和后端服务间高可用的通信服务。本系统采用MQTT协议来完成设备和后端服务间的通信,详细内容请查看"基于MQTT协议的数据收集系统"小节内容。

设备故障处理流程管理

故障处理流程主要是指,运维人员在及时获得设备故障信息后,所做的一系列操作总和。这里假设所有的运维人员具有相等的处理能力。那么处理的效率主要体现在流程的时间成本和相关人员的沟通成本。
假设一个场景:

  1. 运维A和运维B同时收到设备E的异常信息,AB同时去处理,处理过程中A先修复了问题,B在处理的时候发现设备E已经得到修复了,然后B(如果有心的)可能会询问同事有谁解决了设备E的问题。A回复他解决了,这时B才会放下设备E的问题,去关注其他设备的问题。

这个过程中非常形象的显示了不规范化的流程导致的人力浪费和处理的效率低下。
WorkOrder.jpg-19.5kB
如上图所示,解决这个问题最有效的方案就是建立工单系统。异常发生时建立异常工单,并分配到负责人。负责人由上下游关系,上游处理不了需要将工单指派至自己的下游来处理。如果到链条的末端还未能有效解决,则挂起工单,交由相关厂商解决。

分析总结

远程设备管理本质上就是及时获取设备的故障状态,并由运维人员高效的处理以使设备能够以最高的有效率来提供服务。在此基础上要建立高效完善的项目发布体系来满足业务的迭代需求。
在上面的小节中,我们分析了每一个管理模块的核心问题以及解决方案。下面将针对整套方案中的两个核心问题进行详细介绍:

基于MQTT协议的数据收集系统

数据收集系统包含两个子模块,数据收集和数据处理。数据收集负责获得数据,数据处理负责数据清洗和分组归类并持久化。
dataCollecSystemMain (1).jpg-10.1kB

数据收集

分析现有需求场景

我们先来假设,如果要通过http来解决上述场景我们需要做什么工作。

ConnWithHttp (1).jpg-41.2kB
如上图所示,基于目前的系统结构,至少(实际情况要远远比上图复杂)需要完成以下工作:

当然实际开发中远不止上面两种映射。so!本末倒置(很大精力集中在了通信可靠的协议设计上)的通信设计不仅耗费巨大的人力成本,而且还不一定会达到什么效果。

基于MQTT的通信方案

什么是MQTT?

  1. MQTT is a machine-to-machine (M2M)/"Internet of Things" connectivity protocol. It was designed as an extremely lightweight publish/subscribe messaging transport. It is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is at a premium.

简单的说,MQTT是一个轻量的发布订阅模式消息传输协议,专门针对低带宽和不稳定网络环境的物联网应用设计。

MQTT协议的特点:

  1. 采用Publish/Subscribe模式,提供一对多的消息分配。
  2. 基于TCP/IP网络连接。
  3. 提供三级Qos支持,保证可靠传输:
  4. 1."At most once",最多一次;
  5. 2."At least once",至少一次;
  6. 3."Exactly once",确定一次;
  7. 1字节固定报头,2字节心跳报文,报文结构紧凑。

发布订阅模式解耦了抽象对象之间一对多的依赖关系,当一个对象的状态发生改变时候,所有依赖于它的对象都将得到通知。
PublisherAndSubcribe.jpg-19.3kB
如上图所示,这个概念非常符合数据收集的通信场景,服务端从繁复的通信维护逻辑中解放出来,服务端只需要subscribe"感兴趣"的异常topic,而设备端只需要public指定的异常topic,这样在异常发生时服务端即可收集到相关的异常数据。并且MQTT提供的三级Qos传输质量,保证了消息传输的可靠性.

具体方案

在通信协议确定以后,接下来的工作主要包括两部分:1.搭建mqtt server,并开发适用于后端服务和设备软件模块的mqtt client。2. 将mqtt协议应用到异常数据收集方案中。

构建MQTT消息系统
  1. 搭建MQTTServer
    "闭门造车"的写一套基于MQTT协议的消息系统得不偿失。由于MQTT协议是开放协议,所以在开源领域已经有很多成熟的实现了MQTT协议的sever。经过对比、测试、筛选,最终我选定EMQ开源消息服务器来承担MQTT的server。

什么是EMQ?

  1. EMQ 2.0(Erlang/Enterprise/Elastic MQTT Broker)是基于Erlang/OTP语言平台开发,支持大规模连接和分布式集群,发布订阅模式的开源MQTT消息服务器。EMQ 2.0完整支持MQTT V3.1/V3.1.1版本协议规范. EMQ 2.0 消息服务器支持单节点100万连接与多节点分布式集群.

为什么选择EMQ?

  1. - 开源,并且稳定版本已经更新到2.0
  2. - 完整支持MQTT V3.1/V3.1.1版本协议规范
  3. - 支持分布式集群
  4. - 经过严格的测试,在一台8核心、32G内存的CentOS服务器上,MQTT连接压力测试可以到130
  5. - Erlang/OTP是出色的软实时(Soft-Realtime)、低延时(Low-Latency)、分布式(Distributed)的语言平台

高可用emq集群
image_1beo0kn7fk6q1lri6t83bm52g5l.png-26.9kB

如上图所示,集群中节点间通过TCP互联,消息传递的方式通信。节点由唯一的节点名称标识,节点间通过名称进行通信寻址。每个节点上会运行一个端口映射服务程序-epmd,epmd在节点主机上自启动,负责映射节点名称到通信TCP的端口号。在安全性上,节点间通过一个相同的cookie进行互联认证。MQTT客户端订阅主题时,所在节点订阅成功后广播通知其他节点:某个主题(Topic)被本节点订阅。MQTT客户端发布消息时,所在节点会根据消息主题(Topic),检索订阅并路由消息到相关节点。EMQ消息服务器同一集群的所有节点,都会复制一份主题(Topic) -> 节点(Node)映射的路由表。

2.构建MQTTClient
client端基于eclipse paho的java版本进行二次开发。主要完成以下功能:

  1. -封装了共享订阅特性,提供以组为单位订阅消息。
  2. -屏蔽Client连接Server的交互细节。
  3. -简化消息订阅流程和发布流程。
  4. -完善断开重连机制,保证高可用。
  5. -优化ClientServer的心跳机制,使其符合现实网络环境。

构建完成后,emqClient作为独立模块可以被任何业务系统引用。真正做到0接入成本,傻瓜式的上手过程。在暴露给业务端的接口中,开发人员只需关心我需要定制什么主题,发布什么主题即可。

MQTT协议业务应用

上述通信系统的搭建完成只是整套数据收集系统的一个基础。要将上述通信系统,真正应用的业务(比如设备的异常数据收集)中,还需要做很多工作。

  1. - 异常分类汇总,制定分组Topic和组内元素Topic
  2. - 制定无效消息过滤规则,减少垃圾消息处理。
  3. - 设计可靠的数据持久化方案。
  4. - 打通公司通用报警监控平台。

上述内容不是本文重点,故在此不做详细表述。

总结

目前基于MQTT的数据收集系统已成功在线上运行半年以上,每天异常信息收集数十万条。并基于此收集系统完成的监控报警有效的提高了设备整体运行效率,区域有效率达98%以上。
并且该系统目前已成功运用到其他业务线:
image_1bep6tok91hr7i331aej1821ock62.png-45kB

基于P2P的文件传输系统

公司与业务区域间的网络采用专线连接,由于带宽受限,业务流量和边缘服务流量共享。如果升级包完全通过专线来下载完成,势必会严重影响业务。严重时,甚至可能中断线上业务,导致故障。当然可以通过网络设备限速来避免这种情况,那么上千台设备的升级部署将会是一场噩梦。
于是基于P2P的文件传输系统由此诞生。方案的设计灵感来源于同事的一句玩笑。在现实的业务场景中,远程设备按区域部署。区域内部搭建局域网,也就是说一个区域内的远程设备网络互通。如果我们打破传统的Client/Server (C/S)下载模式,引入Peer-to-Peer概念,那么文件传输的问题即可完美解决。即使远程设备扩展至几十万台,一个升级包(假设升级包小于1M)的传输完成也不过十几分钟。P2P技术的详细文档和目前发展状态大家可以自行Google,文档多到让你看的眼睛发软。

方案

从字面上,P2P可以理解为对等互联网。所以P2P本质上也是一个网络。只不过在网络中的每个结点的地位都是对等的。每个结点既充当服务器,为其他结点提供服务,同时也享用其他结点提供的服务。具体到公司的现实场景,要想实现文件的高效传输,首先需要在每个逻辑区域建立起p2p网络。
需要注意的是,设备每天都会定时的开关机,所以一个显然的问题必须面对,即这个P2P网络需要每天重新建立。所谓"日出而建,日落而散"。

创建P2P网络

选取路由协议

P2P作为一门学科,其发展历程中经历了多次更新换代,节点定位算法和路由协议也有多个成熟的方案。历史过程在此不做表述。本系统采用Pastry搭建P2P网络。

  1. Pastry is a generic, scalable and efficient substrate for peer-to-peer applications. Pastry nodes form a decentralized, self-organizing and fault-tolerant overlay network within the Internet. Pastry provides efficient request routing, deterministic object location, and load balancing in an application-independent manner. Furthermore, Pastry provides mechanisms that support and facilitate application-specific object replication, caching, and fault recovery.

详细内容请参考FreePastry官网

动态创建P2P网络

简单的创建逻辑如下图所示。初始节点会创建初始网络,网络中只有自己一个网络节点(192.168.0.1)。设备192.168.0.2在加入网络前,会从网络控制中心获取当前网络信息,得知已有节点(192.168.0.1)初始化了网络,那么它(192.168.0.2)会直接请求初始节点(192.168.0.1)加入网络。设备192.168.0.3重复设备192.168.0.2的流程依次加入网络。这样一个限制在局域网的P2P网络就成功了。
CreateNet.jpg-27.5kB
当然现实场景要比这个简化图复杂的多,需要考虑以下问题:

  1. 多节点同时加入网络引起的多线程问题。
  2. 节点存活状态监测。
  3. 节点P2P生命周期维护(在纯自发的P2P网络中,几乎不可能维护所有节点的网络状态)。

所以网络的动态创建需要一个网络控制中心来协调完成,网络中心的具体功能可以参考下面的分析。

多线程问题

按一个区域内的设备为例分析,一个节点的P2P网络生命周期有三种种:离线状态,等待状态,在线状态。他们之间的转换关系如下:
NetStatus.jpg-14.6kB
网络的初始创建需要有初始节点完成,初始节点的选取是公平性的先到先得原则。初始节点的资格具有唯一性,即只可能有一个初始节点。这个唯一性通过REDIS的原子操作(hsetnx)保证。获取资格失败的节点则进入等待队列等待初始节点完成初始化。而等待状态和在线状态也分别由相应的临界容器保证数据的一致性,这两个临界容器的原子操作通过REDIS的ZSET完成。
具体细节如下图所示:
CreateNetDetail (3).jpg-44.6kB
中间的长方形代表的是网络控制中心,内部的虚线代表节点X可能的路径。网络控制中心包含三部分:

以示例说明,节点X申请加入网络,系统会首先判断当前区域是否完成了网络的初始化,如果没有完成初始化,则节点X尝试去获取InitToken(此处有临界资源),如果获得令牌失败则进入WaitQueue(此处有临界资源)等待,否则直接初始化自己为初始节点并成功进入ReadySet(此处有临界资源)。这里会有一个定时任务,每隔一段时间去查看WatingQueue中是否有正在等待的节点,如果有则会去确定之前初始的节点成功了没有,如果成功了,则直接告诉等待节点集去加入网络,否则需要从WaitingQueue中选一个节点重新初始化。当然一个节点离开网络后,需要通过某种机制知道此事件的发生,从而把该离开的节点从ReadySet中剔除。

存活状态

存活状态通过MQTT和网络控制中心保持心跳连接来实现,每次收到心跳消息更新节点的存活状态。如果固定周期T内未收到心跳消息,则认为此节点没有存活。

P2P生命周期维护

Pastry是自组织的重叠网络,每个节点都被分配一个128位的nodeId。nodeId用于在圆形的节点空间中(从0到2128-1)标识节点的位置,它是在节点加入系统时随机分配的,随机分配的结果是使得所有的nodeId在128位的节点号空间中均匀分布。基于这种原型的逻辑网络拓扑,在每一个Pastry节点内部都会维护一个叶子节点集合,叶子节点集合维护的是与本地节点在nodeId的距离计算上最接近的节点。集合内一半是nodeId值大于本节点的,一半是nodeId值小于本节点的。叶子节点在整个路由算法中起到了核心的作用。如下图所示,pastry的逻辑网络拓扑结构。
image_1bepjnsmohvk194l1k1u1oio1kc79.png-21.3kB

理解完这些概念后,我们接着分析下一个节点加入和退出会发生什么。
一个新加入的节点按照如下步骤初始化它的状态:

  1. 假设这个节点为XX会联系一个附近的节点A(可以从邻居节点集合中获取),并请求A路由一条使用X作为关键字的特殊信息。这条信息被路由到nodeId在数值上最接近X的现存节点Z。之后XZ获取叶子节点集合,从A获取邻居集合。沿着AZ的路由上遇到的第i个节点中获取路由表的第i行。通过这种算法,X能够正确的初始化它的状态,并通知需要知道它状态的节点(通过是X作为其他节点的叶子节点或邻居节点的节点)自己已经加入网络。

一个已经离开的节点可以通过如下方法获得:

  1. 通常位于互相叶子节点集合中的节点会周期性的交换存活信息,如果在一个给定周期T内,一个节点没有做出反应,就假定它离开网络了。

基于上述分析,我们只需要在心跳信息中加入该节点的叶子节点信息,那么就可以判断出某一个节点的加入和离开状态,从而维护节点的网络生命周期。

文件共享

P2P网络创建完成后,文件共享就是顺理成章的事情。只不过需要考虑现实场景中的限制。需要完成以下工作:

  1. 为获得最高的文件传输效率,需要设计共享算法,并保证一个P2P网络内部只会有一台设备从远程服务端下载。剩余设备通过P2P网络内文件共享获得资源。
  2. 由于业务区域越来越多,而每个区域都至少需要一台设备从远程服务器下载,所以公司主干网的带宽是有限的。需要在区域粒度上对下载进行限流。
  3. 单台设备内部要考虑文件传输的幂等,文件的有效性校验,传输失败的重试机制等。

共享算法和限流算法不算本文的内容重点,故不在详细阐述。

总结

要开发完成一套适用于本公司的远程设备管理解决方案,不是一朝一夕的事情。也不是一篇文章能够阐述完全的。限于篇幅本文只对方案中的核心内容进行了详细分析说明,非核心内容并未着力分析。如果大家感兴趣的话,在后续文章中,我会就方案中的某些设计点展开详述。
从开始到整套系统上线运行,前后花费将近3个月时间,塌坑无数,还好圆满完成任务。需要说明的是,开源项目是一把双刃剑,在获得他的免费特性之后,意味着你需要为它的功能不完善(bug)或者文档不够健全买单。比如,在P2P协议的选取工作中耗费了将近两周时间才确定下来,原因就是在测试开源项目的过程中,一些重大bug影响到了核心逻辑的构建而不得不重新推倒重来。
时间短,内容多,能力有限,分析疏漏之处请各位同行能够细心指出。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注