难怪微服务架构是脸书、网飞和优步等全球企业发布的分布式应用程序的基础。以细粒度隔离服务,然后聚合它们以协同工作,使分布式系统比单片系统更易于管理。
但是,对于嵌入式系统——由物理上嵌入在特定设备中的小型专用计算机组成的应用程序,它们共同朝着一个共同的目的工作——情况有点不同。
与在数据中心内和跨数据中心运行的面向微服务的架构(MOA)不同,嵌入式系统往往在硬件和用例方面具有专业性,例如,在工业装配厂运行一队机器人工人或控制自动驾驶汽车。
面向微服务的架构可以应用于这些类型的环境,但需要特别考虑。当事情出错时,你不能只是旋转另一个容器来替换出现故障的容器。还需要更多。
为嵌入式系统编写面向微服务的架构需要不同的设计和实现方法。本文介绍了这种方法。
面向微服务的体系结构简介
在深入讨论将MOA运用于嵌入式系统的细节之前,不妨先大致了解这种体系结构的基本要素。
面向微服务的体系结构旨在将应用程序的行为分解为一群独立存在但一致行动的离散服务。MOA的工作方式是将离散服务分发到众多远程位置。
通常,这些服务使用一种众所周知的传输协议(比如TCP、UDP或HTTP)发送和接收数据。某种类型的组织、前端客户端机制(比如在桌面或移动设备上运行的网页或原生代码)将各种服务聚集在一起,形成整个应用程序的统一表示。然而如前所述,组成MOA的每个服务都是远程托管的。
应用程序的前端调用远程路由/控制器服务。路由/控制器服务知道组成应用程序的微服务的位置,并根据作为调用代码一部分的某种标识符将调用转发到适当的服务。微服务处理调用,并将结果发回给路由器/控制器作进一步处理——或者如果某个调用完成,则将响应发回给调用客户端。
图1. 面向微服务的体系结构的基本模式
将应用程序分成托管在远程位置的功能这个想法始于远程过程调用(RPC)。MOA通过添加一组常规需求来增强RPC模式。在MOA下,每个微服务:支持单个关注点;是离散的;承载自己的数据;可以传输;是短暂的
以下是这每一项要求的含义:
支持单个关注点
微服务应该将其行为限制在单个关注点上,比如登录服务、订购服务、购买、处理信用卡交易的服务、支持客户配置文件的服务、执行税收计算的服务或日志记录服务。
一个微服务可以使用另一个微服务,比如采购服务可以使用税收计算服务来确定订单的总金额。然而,不应该将两个服务组合到一个代码库或单个部署单元中。
是离散的
微服务应该是离散的,因为它应该被限制在单个部署单元中,并在网络上有清晰的边界。该部署单元可能是Linux容器,也可能是代码工件,比如Java .jar文件、.NET DLL或Rust二进制文件。以嵌入式系统为例,部署单元可能是一个实际的硬件。
微服务的内部组件应该是私有的,公众无法访问。然而,公共访问应该由定义良好的API提供。
承载自己的数据
微服务承载自己的数据,除了通过API外,不与另一微服务共享数据。通常,微服务会有自己的数据库或数据库中隔离良好的表。虽然微服务之间可能出现数据冗余,但这种情形是可以接受的,也是微服务维护自己的操作状态和边界所必需的。
可以传输
微服务必须能够在任何时候传输到任何托管环境。当微服务在一台发生故障(比如断电)的机器上运行,又必须重新部署到另一台正常运行的机器上时,可传输性非常重要。
是短暂的
微服务必须能够按需创建或销毁。在微服务执行高强度计算、只需要满足暂时需求的情况下,这一点尤为重要。比如说,微服务对特定的视频文件执行特效处理。
面向嵌入式设备的MOA有何特别之处?
与为数据中心应用程序编写MOA相比,为嵌入式环境实施MOA需要不同的方法。
首先,大多数数据中心使用Linux操作系统来驱动机器。Linux是一个功能齐全的操作系统,占用大量的内存和磁盘空间。即使是Alpine之类精简版的Linux发行版(只有一些基本功能),这个操作系统也占用5MB的存储空间。
许多嵌入式芯片(比如EPS32)搭载大约520KB的内部内存,其中一些容量专用于非易失性存储。使用特殊配置时,一些芯片可能拥有高达4MB的内存和2MB到16MB的闪存。
不过,当嵌入式设备的存储量有限(小于4MB)时,Linux无法工作。相反,嵌入式设备通常使用某种版本的实时操作系统(RTOS)。ESP32芯片组上使用的FreeRTOS操作系统只需要5 KB到10KB的代码存储,内存使用低至300 KB。正如您所见,与数据中心中运行的机器相比,嵌入式设备的系统需求非常小。
此外,虽然Linux支持容器,允许多个微服务在虚拟机集群中运行,但在嵌入式系统中,容器支持更多的是一种例外,而不是常态。通常,微服务将在专用的嵌入式微处理器上运行。微服务和运行微服务的硬件之间的一对一关系影响了部署和升级微服务的方式。
这不是使用Kubernetes之类的容器管理框架来重新部署容器的问题。相反,要进行升级,需要直接连接到嵌入式处理器,并且在许多情况下需要停用作为升级目标的设备。
比如说,升级运行汽车制动系统的微服务需要汽车没有在路上行驶、处于静止状态。
简而言之,为嵌入式系统部署和升级微服务的过程高度依赖系统硬件的物理状态,但是还有另一个重要的限制因素:数据交换。
嵌入式设备之间的数据交换最好使用二进制数据格式来实施。嵌入式处理器中的空间和带宽容量有限,因此基于文本的格式(比如XML和JSON)不能很好地工作。
相反,像协议缓冲区这样的二进制格式或自定义二进制格式更适合MOA场景中的通信,在这种场景中,体系结构中的每个微服务都托管在嵌入式处理器上。
然而,本身在特定设备(比如汽车)内运行的嵌入式处理器和外部设备(比如手机)之间进行数据交换需要特别考虑。大多数嵌入式处理器在小型迷你板上搭载其他芯片,如图2所示。
图2. ESP32迷你板支持蓝牙和Wi-Fi通信
这些迷你板内置蓝牙和Wi-Fi功能。嵌入式芯片组可以使用这些功能与板外设备进行通信。在嵌入式芯片组根据已知格式与已知外部设备通信的情况下,使用二进制格式进行通信仍然是切实可行的。
在某些情况下,比如使用HTTP与远程Web API通信时,较笨拙的基于文本的数据格式是规定的数据交换方式。考虑到芯片在存储和内存方面的限制,让每个嵌入式芯片组参与基于文本的通信可能是个问题。
另一种方法是使用专用代理芯片组与外部设备进行通信,该芯片组支持HTTP,并拥有增强的存储和内存功能。专用代理负责管理来自其他板载嵌入式处理器的外部目标的通信。(参见图3。)
图3. 外部目标的专用代理使嵌入式芯片组能够有效地通信
服务路由是另一个需要考虑的问题。正如数据中心中运行的MOA需要API网关将流量路由到指定的微服务一样,嵌入式环境中运行的MOA也需要这样的路由器/控制器机制。在一辆汽车中,路由器/控制器是在汽车控制器局域网(CAN)上运行的电子控制单元(ECU)。(参见图4。)
图4. 汽车中的CAN使用电子控制单元(ECU)来协调嵌入式设备上运行的微服务之间的数据交换
ECU可以感知汽车内运行的所有组件,并据此制定路由路线。此外,ECU还可以是维护全局状态的控制点。
许多传统的分布式应用程序可以在不需要应用程序中的每个微服务立即了解应用程序整体状态的情况下运行。然而,了解系统的整体状态对于在嵌入式系统中运行的微服务非常重要。
比如说,当自动驾驶汽车中的传感器看到道路上的障碍物时,制动系统需要知道车辆处于危险的全局状态,以便做出相应的反应,因此需要普遍感知全局状态。
飞行控制系统(FCS)和楼宇管理系统(BMS)也有维护和报告全局状态的机制。在FCS中,控制机制名为飞行管理系统或飞行管理计算机。
在BMS中,该组件名为楼宇自动化控制器或楼宇自动化系统控制器。楼宇自动化控制器报告楼宇中所有子系统的状态,比如暖通空调、照明、安全、电梯、电气系统和消防安全设备。
需要理解的重要一点是,任何嵌入式系统都需要一种路由机制来协调组成系统的各种设备之间的流量和数据交换。
把它们组合起来
从智能家居、自动驾驶汽车到机器人运行的工厂,物联网和智能设备呈爆炸式增长,为精通面向微服务体系结构的软件开发人员提供了处理嵌入式系统的更多机会。
将面向微服务的体系结构运用于嵌入式系统需要一些新知识,还需要与用于创建在数据中心虚拟化环境中运行的业务应用程序的平常做法略有不同的软件开发方法。但考虑到面临的机会,有望获得重大的投资回报,值得我们应对这一挑战。
参考链接:https://thenewstack.io/how-to-apply-microservice-architecture-to-embedded-systems/?utm_referrer=https%3A%2F%2Fwww.51cto.com%2F