本篇文章我们将探索集成多个开源应用程序以构建物联网边缘分析技术栈,该技术栈旨在基于 ARM 的低成本边缘节点上运行。我们将使用该技术栈来收集、分析和可视化 IoT 数据,而无需先将数据传送到云或其他外部系统。
一、云原生原理和组成
边缘
边缘计算是一种快速增长的技术趋势,涉及将计算能力推向网络边缘。维基百科将边缘计算描述为一种分布式计算范式,它使计算和数据存储更接近缩短响应时间和节省带宽所需的位置。术语边缘通常是指位于网络边缘(边缘设备)的计算节点,靠近数据源,位于数据源和外部系统(如云)之间。在他最近的帖子中,边缘计算的 3 个优势(和 1 个劣势)著名的未来学家 Bernard Marr 认为,降低带宽要求、减少延迟以及增强安全性和隐私性是边缘计算的三大主要优势。
Quiss Technology PLC 的营销主管 David Ricketts 在他的帖子“云和边缘计算——2018年你需要知道的统计数据”中估计,到 2022年,全球边缘计算市场预计将达到 67.2 亿美元的复合年增长率率高达 35.4%。意识到市场潜力,许多主要的云提供商、边缘设备制造商和集成商正在迅速扩展其边缘计算能力。例如,AWS 目前在其边缘计算类别中提供十多种服务。
物联网
边缘计算经常与物联网 (IoT) 相关联。物联网设备、工业设备和传感器生成的数据通常通过边缘节点(例如物联网网关)传输到其他内部和外部系统。物联网设备通常会生成时间序列数据。根据维基百科,时间序列是一组按时间顺序索引的数据点——在连续的等间隔时间点取得的序列。物联网设备通常会生成连续的大容量时间序列数据流,通常达到每秒数百万个数据点的规模。物联网数据特性要求物联网平台最低限度地支持时间准确性、大容量摄取和处理、高效的数据压缩和下采样以及实时查询功能。
IoT 网关等边缘设备将 IoT 数据从这些设备聚合并传输到外部系统,它们的功率通常较低,处理器、内存和存储空间有限。因此,物联网平台必须满足物联网数据的所有要求,同时支持资源受限的环境。
边缘物联网分析
领先的云提供商 AWS、Azure、谷歌云、IBM 云、甲骨文云和阿里云都提供物联网服务。许多提供具有边缘计算功能的物联网服务。AWS 提供AWS IoT Greengrass。Greengrass 为边缘设备提供本地计算、消息传递、数据管理、同步和机器学习 (ML) 推理功能。Azure 提供Azure IoT Edge。Azure IoT Edge 提供了在使用标准容器的边缘设备上运行人工智能 (AI)、Azure 和第三方服务以及自定义业务逻辑的能力。Google Cloud 提供Edge TPU。Edge TPU(张量处理单元)是谷歌专门构建的专用集成电路(ASIC),旨在在边缘运行人工智能。
物联网分析
许多云提供商还提供物联网分析作为其物联网服务套件的一部分,尽管不是在边缘。AWS 提供AWS IoT Analytics,而 Azure 提供Azure Time Series Insights。Google 通过下游分析系统和使用Google BigQuery 的临时分析或使用Cloud Machine Learning Engine 的高级分析和机器学习间接提供物联网分析。这些服务通常都需要将数据传输到云进行分析。
二、云原生应用的设计
云原生应用从上层架构来看,包括精益运营、安全性、可靠性和可用性、可扩展性和成本这个五大支柱,我们主要从以下几个技术实现层面来讲讲。
API设计和版本控制
因为API是其他服务用来与你的服务进行通信的接口,因此正确地记录和版本化API至关重要
三种策略:
无版本
API只有一个版本,API的调用者永远只调用最新的API。当API接口发生更改时,所有使用者也需要跟着改。对于调用者而言,这是最昂贵的方法,因为每次发布新的API版本时,他们都必须升级。
点对点
所有版本的API都在正常运行,每个调用者都使用他们需要的版本。调用者可以根据需要迁移到新版本。与无版本相比,这对调用者来说是一个更好的策略,但是对于API开发人员而言,维护较旧的API版本成本很高。
兼容性版本控制
所有调用者都使用最新的API版本。旧版本的API会被舍弃,但是最新版本的API是向后兼容的。
研究结果表明,兼容性版本控制策略是最高效的。尽管对API的开发者而言,它确实会带来一些额外的工作,因为需要保持向后兼容性。
REST本身不提供任何特定的版本控制约定,但有三种方法来实现版本控制:全局版本控制、资源版本控制和基于mime的方法。这些方法中的每一种都有其优点和缺点,这里没有明确的最佳方法。
迄今为止,使用语义版本号几乎已经是一种标准做法了。语义版本号(major.minor. patch)可以清晰地告诉你应该增加版本号的哪一部分:
- 当你修改了API,使其不再向前兼容时,应该增加主版本号(major)。
- 当你用向后兼容的方式增加了一些功能时,应该增加次版本号(minor)。
- 当你用向后兼容的方式解决了几个Bug时,应该增加补丁版本号(patch)。
服务间通信
网络和服务通信是分布式系统最基础的话题,它们对一个应用的性能起着至关重要的作用。因此,理解各种服务间的通信方案对于你设计和构建云原生应用是非常有帮助的。从大致上来讲,你可以把服务间的通信分为两类,一类是外部服务通信,另一类是内部服务通信
通信协议
大多数情况下,HTTP协议会被用来作为客户端和云原生应用程序之间的通信协议。但是,它并不是性能最高的协议。
一个大型的微服务架构下的应用程序可能由数百甚至数千个微服务组成,服务越多,需要进行的通信和数据交换就越多。因此,所选择的协议成为影响性能的重要因素,并且更改生产环境下的服务通信协议的代价可能会相当大。
其中websocket、http2/2、gRpc等几个常用的协议,它们已经被证明可以为云原生应用带来更好的性能。
消息协议
云原生应用经常会和事件驱动和基于消息的架构结合起来,消息传递协议有很多,如STOMP、WAMP、AMQP和MQTT等,我们就不在此一一介绍了。
序列化的考虑因素
除了协议外,数据的序列化和反序列化也会对整体性能产生影响,在最糟糕的情况下,它甚至可能会成为瓶颈。
JSON可能是目前使用最广泛的格式。JSON可读性强、自包含且易于扩展,但是它同样会占据相当可观的内存空间,并且在大数据量的情况下,序列化和反序列化的操作可能会很产生很高的开销。
幂等性
无论你是使用同步还是异步的通信方式,都需要确保如果一个相同的操作被重复执行了多次,目标系统中的结果仍将保持不变。能够多次执行同一个操作而不改变结果的特性被称为幂等性。
由于接收方的故障、重试策略等原因,消息可能被重复接收和处理。理想情况下,接收方应以幂等方式处理消息,这样即便消息被重复也不会导致不同的结果。
假设有一个可穿戴设备,它将一些健康数据发送到一个队列中,然后服务端会从队列中读取数据,将其添加到个人健康计分卡中。下面是该设备提交的一个消息的示例:
{ "heartrate": { "time": "2020020307300", "bpm": "89" } }
我们进一步假设由于某些网络故障该操作失败了,接收方无法接收该消息,因此基于重试机制,该设备再次发送了相同的消息。最终,你得到两个相同的消息。如果接收者现在收到这两个消息并同时处理它们,则心率将显示为178bpm,这可能会使大多数人感到担忧。
为避免这样的情况发生,你需要把这样的操作变成是幂等的。确保幂等性操作的一种常见方法是在消息中添加唯一的标识符,并确保仅当标识符不重复时,服务才对消息进行处理。以下是相同消息的示例,但添加了标识符:
{ "heartrate": { "heartrateID": "124e456-e89b-12d3-a456-42665544000" "time": "89" } }
现在,接收方可以在处理该消息之前先检查消息是否已经被处理过。这通常也被称为去重操作。这个原则同样适用于数据更新的场景。这里最核心的意思是你应该将操作设计为幂等的,以便可以重复执行每个操作而不会导致系统的异常。
网关
在微服务和函数计算的世界中,客户端所需的功能通常分布在多个服务和函数上。客户如何知道要请求的服务的接入点是什么呢?此外,如果将现有服务重新部署到不同的接入点或引入新的服务要怎么办?
概括而言,网关可以分为两大类:API网关和应用程序网关。后者不一定与API有任何关系,它们通常用于安全套接字层(SSL)的终结,路由静态资源(HTML、CSS文件等),或路由到对象存储。
路由
路由是网关最常见的功能之一。在这种情况下,网关充当一个反向代理,并将传入的请求路由到后端服务,反向代理通常位于内网中,负责管理用户请求,将其导向正确的后端服务
当客户端需要通过一个统一的接入点进行通信时,该模式很有用。网关负责根据IP、端口、标头或URL将请求路由到对应的各种服务上。因为只需要使用单个接入点,这样就简化了客户端需要实现的逻辑。
实现网关有很多种技术和方法。最受欢迎的网关代理是NGINX、HAProxy和Envoy。所有这些都是反向代理,提供负载平衡、SSL和路由等功能。这些产品都在许多生产环境中经过了实战检验。
服务网格
在云原生的世界中,每个服务都是独立构建和部署的,并且每个服务都可能与其他微服务通信。随着业务的发展,你会开发越来越多的微服务,这也意味着服务之间的通信会增加,并且也会变得更加复杂。
服务间的通信对云原生应用而言很重要,因此你的每个服务都需要具有弹性,并且能够不受任何网络问题的影响。
你需要用一套方法来实现请求重试、超时定义、断路器等机制。写一个具有完善通信功能的库来实现这些是一种方法,但是如果服务是用不同的编程语言来实现的,那这种办法可能对你没有太大帮助。
你可以选择分别为每种语言重写一遍这个库,你最终将得到的是一堆服务,这些服务包含着一部分相同的功能,这些功能是用不同的语言重复实现的。
三、架构示例
在这个示例中,用户可以管理和查看他们家中各种类型设备的信息。这个服务必须能够支持大量并且还在持续增长的房屋、用户和设备。设备的类型也在持续增多,而且家中的设备也会随着用户增加或者更替智能设备而发生变化。
用户可以在任何能够联网的地方,通过单页应用(SPA)或移动应用来管理设备。用户还能收到设备发出的告警,或者云端服务发现的设备告警。
此外,他们还同意设备发送匿名数据给这个服务,以便进行数据分析。这个服务还需要能够满足日益壮大的对集成应用和云端服务感兴趣的开发者社区和家居自动化爱好者的需求。
如下图中展示的那样,设备与云端的服务相连接。设备会以一定的时间间隔往云端服务持续发送大量的遥测数据,同时它们也会从云端获取用户或者其他事件发送来的指令。
用户也可以通过移动应用或者网页连接到云端服务,然后管理和查看家中的设备信息。数据被发送到云端后通常会被存储下来,然后被批量处理和分析。
进一步看下图中有关设备遥测数据存储和分析的服务,可以发现,数据会通过不同的路径传输然后被处理。这种把数据流通过热、温、冷的路径分开处理的架构被称之为lambda架构。
云服务提供商的设备管理服务可以用来让设备连接到云端,AWS IoT Core和Google Cloud IoT Core都是这样的服务
设备也可以通过Web API连接到云后端,但是这样会导致后端服务构建和运维的服务不太理想。这会提高服务的总体成本,也可能造成发布延迟。云原生的一个原则是尽量多使用已有的云服务。
设备通过云服务供应商的设备管理服务来发送遥测数据。遥测数据被写入数据流,它们被不同的订阅者获取。每个订阅者都可以用不同的频率按自己的方式来处理数据流,订阅者之间都是相互独立的。
如下图所示,云服务供应商配置的服务将收到的数据流处理后存储到对象存储中,这有时被称为冷路径。
对象存储价格便宜,并且可以用最少的基础设施和运营成本长时间保留大量设备和用户的数据。然后可以晚点再分析这些数据,并且可以通过长的时间跨度或者根据大量设备来做一些趋势性分析。
另一个订阅者将数数据处理后保存到时序数据库服务中,如Amazon Timestream或者Google BigTable。这些数据被用于更近乎实时的批处理分析,并显示过去一小时到数天内的设备遥测数据。
然后,随着时间的流逝,这个服务中的数据将自动移至速度较慢但是价格比较便宜的数据存储中,并对数据进行下采样,因为随着时间的推移,数据保真度在该数据存储中不那么重要了。
在某个时间点,数据会过期,并且不用再保留在数据存储中。如果需要查询超出时间范围的历史信息,那么系统需要从冷存储中加载它。
可以设计一个从冷存储中获取数据然后重新注入时序存储中的流程,这样可以简化应用读取数据的过程。另一个订阅者负责处理流中的数据,以执行复杂的事件处理或者流分析。
该热路径可以在接收到数据后的很短的一段时间内判断设备状况,时间通常从毫秒到分钟不等。当设备状态接近临界点时,它可以用来生成警报,并发送给用户。
这个智能家居设备管理服务包括一个后端API,供有兴趣与该服务集成的开发人员使用,也会由客户端(移动设备和单页应用)使用。
下图说明了API如何由多种服务组成,其中一些是在Kubernetes集群中运行的容器,而另一些是在云服务供应商的FaaS平台上运行的函数。
团队首选的计算模型是FaaS(函数即服务),但是有一些工作任务是长期运行的或具有复杂的环境要求,有些团队更喜欢容器。应该鼓励各个团队使用最适合实现其需求的计算模型。一些服务通过Kubernetes的Kubelet使用CaaS计算模型来运行某些Kubernetes任务。
API网关用于减轻一些API管理任务。API网关负责对请求进行鉴权并限制发送过多请求的用户,以维护所有使用该服务的用户的服务质量。
下图显示了一个单页应用(SPA),这个应用通过内容分发网络(CDN)为用户提供服务,其背后的数据源来自块存储服务。
SPA通常由静态资源组成,这些静态资源可以通过块存储进行存储并提供给用户。CDN可以使客户端快速加载这些静态资源,因为它们被缓存在靠近客户端的地方。
SPA必须具备缓存清除的技术,例如如果资源已更改,那么需要更新哈希值,或者在将更新推送到存储时使CDN缓存中对应的资源失效。这些任务可以在持续交付的流程中实现。
参考书籍《Cloud Native——Using Containers, Functions, and Data to Build Next-Generation Applications》
文丨Soundhearer
图丨来源于网络