吴昌雨,李云松,刘 青,王善勤
滁州职业技术学院信息工程系,安徽滁州,239000
基于微服务架构的物联网应用基础框架设计
吴昌雨,李云松,刘 青,王善勤
滁州职业技术学院信息工程系,安徽滁州,239000
为构建具有分布式、开放式特性的物联网生态系统,提出了基于微服务架构(MSA,Micro-service Architecture)的物联网应用基础框架。以农作物生长环境采集系统为载体,阐述了其运行与交互方式,并展示了原型系统实现方法。该框架采用去中心化设计,具有易于访问、易于实现、易于扩展等特性,从应用层面提出了一种解决物联网异构问题的解决方案。
微服务;物联网;应用基础框架
物联网(Internet of Things,IoT)是指通过部署具有一定感知、计算、执行和通信等能力的各种设备,获得物理世界的信息,通过网络实现信息的传输、协同和处理,从而实现人与物通信、物与物通信的互联的网络[1]。国际标准化组织协会等组织在物联网产业化及标准化上开展了大量工作,产生了许多较为成熟的低功耗的物理层和传输层网络协议,如Zigbee、Bluetooth、IEEE 802.15.4等,各种物联网设备在这些协议的支持下可以实现物联网设备之间的互联互通。然而,这些技术标准虽然从网络层角度实现了物联网设备的互联互通,但从应用层的角度看,这些异构的物联网设备间仍然是一个个信息孤岛,还需要开发者将其整合才能成为一个具有应用价值的物联网应用系统。
以物联网农作物生长环境采集系统为例。该系统包含大量传感器、物联网设备,通过无线传感器网络框架(Wireless Sensor Network,WSN)可以解决设备与设备之间的大规模部署及互联互通问题,然而物联网系统用户、应用及设备之间的交互及信息共享等需求则需要由应用层来解决。本文提出的基于微服务架构的物联网应用基础框架设计方案适用于对开放性、可扩展性有较高要求的物联网应用系统,从应用层面解决物联网异构问题。
通过研究当前物联网产业现状可以发现,虽然目前物联网产业化应用取得了一些成果并积累了不少成功的案例,但从应用系统架构设计角度看仍然存在一些共性的问题:一是架构设计封闭,采用私有接口、协议实现通信,即使是同行业间的应用也没有互操作能力;二是缺乏异构终端支持,由于不同类型终端信息处理方式及通信协议的差异,现有系统很难实现跨终端应用支持;三是采用整体架构模式(Monolithic Architecture)设计,所有功能封装在一个应用系统中,系统水平扩展性差且缺乏跨应用的支持;四是系统耦合性高,聚合度低,程序难以复用与维护,与低耦合高内聚的软件开发原则相悖。
为解决这些问题,业界针对物联网应用基础框架设计制定了许多可借鉴的标准和方案,如Device Profiles for Web Services(DPWS)标准将SOA应用于物联网[2]。该标准基于Web Services 设计,可以通过服务总线及中间件实现智能设备及应用软件的交互,但SOA标准更适用于整合连接静态的企业级大型应用。另一种值得关注的方案是近年来才提出的一种开放式物联网方案Web of Things (WoT)。该方案主张将所有的物联网设备抽象为资源,通过REST Web Service API的方式将其公开,在这一方案基础上Pautasso等人提出了基于REST的业务流程管理方案(Business Process Management,BPM),允许将复杂的业务流程抽象为RESTful Web Service。BPM方案对于Web2.0及企业应用整合有重要参考价值。
上述标准和方案大都基于整体架构模式设计,即采用集中式业务平台处理业务逻辑及存储数据。在物联网的复杂环境中,这种方式必然带来一些系统扩展性及伸缩性方面的局限,比如整体架构模式采用统一的技术手段实现,应对异构环境缺乏针对性;系统水平功能模块扩展需重新构建和部署整个系统;除重写整个应用程序外,很难变更新的基础框架,其结果是整体架构无法支持复杂的、变化的、长期的应用。
物联网应用基础框架设计既要考虑如何将现有的物联网设施整合,同时也要考虑系统设计的开放性及可扩展性,比如是否能够快速地适应在现有基础设施上的传感器与物联网设备增加而导致的功能需求变化,因此在设计过程中应遵循以下几点准则:(1)系统设计简洁,易于实现。系统设计应尽量简洁,避免复杂的架构与技术方案,支持系统的快速原型化。(2)基于标准,降低开发成本。尽量采用已被广泛接受且易于实现的标准及协议来构建系统,降低开发成本及开发门槛。(3)采用轻量级通信机制,易于访问。避免复杂的具有平台限制的协议,易于实现及访问。(4)分布式、松耦合,易于扩展。采用分布式设计,避免组件紧耦合设计,以利于系统的水平扩展及垂直扩展。
基于以上准则,在物联网农作物生长环境采集系统的设计过程中提出了采用微服务架构(MSA,Micro-service Architecture)构建应用基础框架。其基本思想是:将功能分解到各个离散的服务中,以实现对解决方案的解耦,即将复杂系统拆分为一系列小且功能专一的服务;并通过相互协作来构建应用系统。实践中,将系统拆分为7个微服务,比如其中湿度控制服务(Temperature control Service)用于获取和记录土壤湿度信息等功能,定时任务服务(Timing task Service)用于配置和完成诸如定时浇灌任务等功能。可见,每个服务的功能小且专一,各自完成整个系统的部分功能。服务与服务间可以通过协作完成复杂的系列任务,比如定时浇灌功能的实现需要由定时任务服务来设置及发布任务、由湿度控制服务来监测当前土壤区块湿度平均值、由设备状态服务来控制智能浇灌设备的开关。基于微服务的物联网农作物生长环境采集系统应用层架构如图1所示。
图1 基于微服务的物联网农作物生长环境采集系统应用层架构
从架构图中可以看出,系统中每个服务的功能及数据相对于其他服务是独立的,服务之间通过HTTP协议实现通信,下面通过与土壤湿度控制相关的三个应用场景中具体的业务来说明该微服务架构如何工作:任务1“获取设备编号为Hum01的湿度传感器当前值”,任务2“获取区域编号Area01的土壤区块湿度信息列表”,任务3“定时监测某区域湿度信息,平均值低于临界值时启动自动灌溉装置”。
对于任务1“获取设备编号为Hum01的湿度传感器当前值”、任务2“获取某区域湿度信息列表”,实现过程较为简单,其业务流程都是通过HTTP协议访问预先定义的资源获取信息,如客户端通过Get请求发送URI:…/humidity/device/Hum01访问资源,湿度控制服务接收请求并返回包含Hum01的湿度传感器当前值JSON格式的响应;客户端通过Get请求发送URI:…/humidity/area/Area01访问资源,湿度控制服务接收请求并返回包含Area01的土壤区块所有湿度传感器当前值列表的JSON格式响应。图2展示了这两个任务的业务流程序列图及其请求、响应样例。
图2 任务1、2业务流程序列图及请求、响应样例
对于任务3“定时监测某区域湿度信息,平均值低于临界值时启动自动灌溉装置”,实现过程相对复杂,需要三个微服务协同工作,其业务流程首先是由定时任务服务通过发送包含有灌溉区域编号、目标湿度值的POST请求至URI:…/humidity/irrigation/,湿度控制服务接收请求后首先会监测该区块平均湿度值,如未达到目标值则发送包含由设备状态操作代码(启动设备)的PUT请求至URI:…/device/{device.id},由设备状态服务接收请求并启动相应的智能灌溉设备,灌溉过程中湿度控制服务还需监控该区块湿度值的变化,一旦达到目标湿度值则再次发送包含由设备状态操作代码(关闭设备)的PUT请求至URI: …/device/{device.id},由设备状态服务接收请求并关闭相应的智能灌溉设备以最终完成灌溉。图3展示了该任务的业务流程序列图及其请求、响应样例。
图3 任务3业务流程序列图及请求、响应样例
上述应用场景所描述的业务流程代表了整个物联网农作物生长环境采集系统业务流程的处理方式,服务和服务之间、服务与应用之间通过轻量级的机制实现彼此间的通信,系统设计采用Web标准中的HTTP1.1这种与语言、平台无关的协议来传输数据。基于HTTP协议构建的RESTful(REST风格的Web服务)API 的接口包含标准的HTTP方法,如GET、POST、PUT和DELETE。表1描述的是以土壤湿度控制服务为例所设计的API接口使用样例。
从表1中可以看出,土壤湿度控制服务的资源命名空间为“humidity”,与土壤湿度相关的操作可以通过该命名空间访问。另外在表格中“获取某湿度传感器当前湿度值”与“删除某湿度传感器记录值”URI示例路径一致,服务器将根据请求类型是GET还是DELETE来确定执行何种操作。当其他应用或服务通过URI访问当前土壤湿度控制服务提供的功能是,通常情况下该服务会返回一个JSON格式数据,比如希望获取某传感器历史湿度记录值,可以通过访问URI:…/humidity/device/{device.id}/{startTime}/{endTime}得到以下返回值:
{["humDvice.id":"hum01","humidityValue":6,"recordTime":"2014-10-1 19:20:01"],
["humDvice.id":"hum01","humidityValue":5,"recordTime":"2014-10-1 19:30:01"],
["humDvice.id":"hum01","humidityValue":5,"recordTime":"2014-10-1 19:40:01"],……}
表1 土壤湿度控制服务RESTful API
此外,对于服务与物联网设备间的通信,在系统设计中同样也采用HTTP协议来实现,图4描述了其结构。当然,这种方式需要在下位机网关将无线传感网络采集到的物理设备数据转换为HTTP协议并传输。
图4 微服务与物联网设备的交互
该微服务架构的主要特点归纳如下:
(1)去中心化设计。每个服务相互独立运行在一个独立的操作系统进程中,可以将不同的服务部署于不同的主机,适应于构建分布式物联网应用系统。由于服务的独立性,每个服务都可以选择不同的技术平台、数据库实现,可以根据不同的业务特征有针对性地选择合适的技术方案去解决具体的业务问题,比如使用Node.js构建定时任务服务,使用Grails构建湿度控制服务等。并且,由于每个服务的功能单一,在定义好接口的情况下,可以由不同的开发团队独立开发而互不干扰。
(2)面向资源的架构(Resource Oriented Architecture,ROA)风格。继承Web of Things (WoT)中将所有的物联网设备抽象为资源的做法,通过微服务将各种资源以REST Web Service API对外公开,REST作为一种分布式软件架构风格,是一系列实现Web标准(基于HTTP 1.1和URI)的指导原则。REST所制定的指导原则使得该架构可以支持“系统组件间交互的可扩展性、接口的一致性、组件的独立部署、降低交互延时的中间组件、安全性的加强、对遗留系统的封装”[3]。
(3)开放式设计。由于整体架构模式系统单进程的局限性,水平功能扩展时只能基于整个系统进行扩展,新功能的发布意味着要重新构建和部署整个系统。而该架构则可很好解决系统伸缩性的扩展问题,比如当系统需要增加一个通风控制相关功能模块时,可以单独开发一个微服务并部署,不会对系统的其他服务产生影响。这意味着该架构可以实现细粒度的自由扩展。并且,由于所有的微服务都是基于REST Web Service API对外公开,很容易在此基础上开发新的应用或实现跨应用间的交互。
微服务架构的实施同样也存在一些挑战,在实践过程中发现突出的问题有以下两点:
(1)微服务协同事务处理。当一个业务流程需要多个微服务协同工作时,采用传统的分布式事务处理方式会降低系统的可用性,因为它要求事务参与者均可用,在分散且互相独立的微服务中实现起来较为困难,并且包括REST、NOSQL等在内的现代软件技术栈并不支持分布式事务,因此建议采用事件驱动的异步模式来处理事务,其特点是可以将事件的生产者、消费者实现解耦,即简化开发同时也提升了可用性。
(2)分布式系统的复杂性。微服务通过REST Web Service API相互交互,对于物联网系统而言,在实际运行过程中必须要考虑网络延迟、网络故障、消息序列化等问题,比如当网络出现故障时,微服务间通信中断时如何处理?在物联网农作物生长环境采集系统中,通过设计消息总线(Message Bus)实现消息队列,微服务可以通过监听消息总线当网络故障恢复时从消息队列中取出滞留的信息。
目前,有许多轻量级的技术框架可以用来实现微服务架构,比如基于Ruby语言的Sinatra Web开发框架,其突出的特点就是轻量、快速[4];基于JavaScript 的Node.js,其特点是借助事件驱动,非阻塞I/O 模型,非常适合运行在分布式设备的数据密集型的实时应用[5];Spring Boot遵循“约定优于配置”的理念,能够极大地简化基于Spring MVC的Web应用和REST服务开发[6]。本文为了实现原型系统快速构建,以基于Groovy语言且同样遵循“约定优于配置”的Grails敏捷开发框架为例,就微服务的实现展开研究[7]。
以湿度控制微服务为例,首先要将资源抽象为领域类,下面的Humidity 领域类(Domain)代码中将湿度相关资源抽象为类的属性,包括设备编号、记录时间等,Grails框架将自动为该领域类动态注入包括save、delete、update、find等方法,即自动提供CRUD等功能支持。
class Humidity {
String deviceId //设备编号
Date recordTime //记录时间
double humidityValue //记录值
static mapping = {
id generator:‘uuid.hex'
}
……
}
其次是基于Humidity 领域类生成HumidityController控制器,控制器用户获取请求并返回响应,下面的代码中show方法用于获取某湿度传感器当前湿度值,以调用Humidity领域类findByDeviceId(该方法由Grails动态注入)方法获取Humidity实例,将结果render为JSON格式并返回。另外,代码中allowedMethods用于定义请求类型与方法的绑定关系,即show方法只能通过GET请求访问,其他类型请求无效。
class HumidityController {
static allowedMethods=[save: "POST",
delete: "DELETE",show: "GET"]
def show(String deviceId) {
def humidityInstance = Humidity.findBy
DeviceId(deviceId)
if (!humidityInstance) {
render(status: 404)
} else {
render(contentType: "text/json") {
humidityInstance(deviceId:humidi
tyInstance.deviceId,
humidityValue:humidityInstance.
humidityValue
)
}
}
}
……
}
由以上代码示例可见,在合适的开发框架支持下,开发一个微服务相对于传统软件开发技术更为简单、快速。即使是完整的湿度控制微服务,其代码量仅约1 000行。当然,编码工作量的降低并不意味着功能打折,只能更加充分地说明合理的设计加上适当的技术将大大降低开发成本与开发门槛。
如上所述,采用微服务架构设计的应用基础框架将系统按照功能拆分为若干微服务,每个服务专注于完成各自核心的业务逻辑,这种微服务架构设计的物联网应用基础框架从应用层面解决了物联网异构问题,适用于对开放性、可扩展性有较高要求的物联网应用系统。此外,其分布式、开放式设计特性易于实现跨应用的交互,从而可以将不同的物联网应用系统整合为物联网生态系统。
[1]孙其博,刘杰,黎舞,等.物联网:概念、架构与关键技术研究综述[J].北京邮电大学学报,2010,33(3):1-9
[2]OASIS.Device Profiles for Web Services (DPWS) specification[EB/OL].[2014-12-01].http://docs. oasis-open.org/ ws-dd/ns/dpws/2009/01
[3]Roy Thomas Fielding.Architectural Styles and the Design of Network-based Software Architectures[D].California Department of Information and Computer Science,University of California Irvine,2000:5-8
[4]Blake Mizerany.Sinatra Documentation[EB/OL].[2014-12-15].http://www.sinatrarb.com
[5]Google Nodejs.API DOCS[EB/OL].[2014-12-20].http://www.nodejs.org/api
[6]SpringSource.Spring Boot Documentation[EB/OL].[2014-12-21]. http://http://spring.io/docs/
[7]SpringSource.Grails Documentation[EB/OL].[2014-12-21].http://grails.org/Documentation
(责任编辑:汪材印)
10.3969/j.issn.1673-2006.2015.07.025
2015-03-15
安徽省高等学校省级自然科学研究重点项目“基于物联网的农作物生长环境信息采集系统研究——以滁州贡菊生长环境为例”(KJ2014A189);滁州职业技术学院校科重点项目“基于CC2530的ZigBee温室智能无线传感器网络设计”(YJZ-2013-06)。
吴昌雨(1977-),安徽滁州人,硕士,讲师,主要研究方向:软件技术。
TP311.5
A
1673-2006(2015)07-0088-05