嵌入式系统——由小型专用计算机组成,嵌入特定设备的应用程序——需要一种不同的微服务方法。
译自 How to Apply Microservice Architecture to Embedded Systems,作者 Bob Reselman。
微服务 架构是全球企业(如 Facebook、Netflix 和 Uber)发布的分布式应用程序的基础,这并不奇怪。将服务细粒度地隔离,然后将它们聚合在一起协同工作,使得分布式系统比单体系统更容易管理。
但是,对于嵌入式系统(由小型专用计算机组成,这些计算机物理嵌入在特定设备中,共同协作以实现共同目标的应用程序)来说,情况略有不同。
与在数据中心内和跨数据中心运行的微服务架构 (MOA) 不同,嵌入式系统往往在硬件和用例方面是专门的——例如,运行在工业装配厂中运行的机器人工作者车队或控制自动驾驶汽车。
微服务架构可以应用于这些类型的环境,但需要进行特殊考虑。当出现问题时,您不能仅仅启动另一个容器来替换故障的容器。需要更多。
为嵌入式系统编程微服务架构需要不同的设计和实现方法。本文介绍了这种方法。
在我们深入探讨将 MOA 应用于嵌入式系统的细节之前,让我们先从对该架构基本要素的总体了解开始。
微服务架构是关于将应用程序的行为分解成独立存在但协同工作的离散服务。MOA 的工作方式是将离散服务分布到各种远程位置。
通常,这些服务使用众所周知的传输协议(如 TCP、UDP 或 HTTP)发送和接收数据。某种类型的组织、前端客户端机制(例如网页或在台式机或移动设备上运行的本机代码)将各种服务聚合在一起,形成对整个应用程序的统一表示。但是,如前所述,构成 MOA 的每个服务都托管在远程位置。
应用程序的前端调用远程路由/控制器服务。路由/控制器服务知道构成应用程序的微服务的位置,并根据调用代码中包含的某种标识符将调用转发到相应的服务。微服务处理调用并将结果发送回路由器/控制器以进行进一步处理——或者,如果给定的调用已完成,则将响应发送回调用客户端。
图 1:微服务架构的基本模式。
将应用程序分离成在远程位置托管的功能的想法起源于远程过程调用 (RPC)。MOA 在 RPC 模式之上构建了一组传统要求。在 MOA 下,每个微服务:
以下是每个要求的含义:
微服务应将其行为限制在单一关注点,例如:登录服务、订购服务、购买、处理信用卡交易的服务、支持客户资料的服务、执行税务计算的服务或日志记录服务。
一个微服务可以使用另一个微服务;例如,购买服务可以使用税务计算服务来确定订单的总金额。但是,不应将两个服务合并到一个代码库或一个部署单元中。
微服务应该是离散的,因为它应该被限制在一个部署单元中,并且在网络上具有良好的边界。该部署单元可能是 Linux 容器,也可能是代码工件,例如 Java .jar 文件、.NET DLL 或 Rust 二进制文件。在嵌入式系统的情况下,部署单元可能是实际的硬件。
微服务内部应该是私有的,公众无法访问。但是,应通过定义明确的 API 提供公共访问。
微服务应携带自己的数据。这意味着微服务应包含其操作所需的所有数据。例如,登录服务应包含用户帐户信息。
微服务应该是可移植的,这意味着它应该能够在不同的环境中运行。例如,登录服务应该能够在开发环境、测试环境和生产环境中运行。
微服务应该是短暂的,这意味着它应该能够快速启动和停止。例如,登录服务应该能够在需要时快速启动,并在不再需要时快速停止。
为嵌入式环境实现 MOA 需要与为数据中心应用程序编写 MOA 不同的方法。
首先,大多数数据中心使用 Linux 操作系统来驱动其机器。Linux 是一个功能强大的操作系统,在内存和磁盘方面都占用大量空间。即使是像 Alpine 这样的精简版 Linux 发行版,它只包含基本功能,该操作系统也需要 5 MB 的存储空间。
许多嵌入式芯片,例如 EPS32,配备了大约 520KB 的内部 RAM,其中一部分容量用于非易失性存储。当使用特殊配置时,某些芯片可以拥有高达 4 MB 的 RAM 和 2 MB 到 16 MB 的闪存。
尽管如此,当嵌入式设备的存储空间有限,低于 4MB 时,Linux 就无法工作。相反,嵌入式设备通常使用某种实时操作系统 (RTOS)。ESP32 芯片组上使用的操作系统 FreeRTOS 只需要 5 到 10 KB 的代码存储空间,RAM 使用量低至 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 中,该组件称为楼宇自动化控制器或楼宇自动化系统控制器。楼宇自动化控制器报告楼宇中所有子系统的状态,例如 HVAC、照明、安全、电梯、电气系统和消防安全设备。
需要理解的重要一点是,任何嵌入式系统都需要路由机制来协调构成系统的各种设备之间的流量和数据交换。
物联网和智能设备的爆炸式增长——从智能家居到自动驾驶汽车,再到由机器人运行的工厂,以及介于两者之间的所有事物——为精通微服务架构的软件开发人员提供了更多参与嵌入式系统的机会。
将微服务架构应用于嵌入式系统需要一些新知识,以及与创建运行在数据中心虚拟化环境中的业务应用程序所使用的常规实践略有不同的软件开发方法。但考虑到眼前的机会,考虑到潜在的巨大投资回报率,这值得一试。