亚马逊AWS官方博客

迁移物联网平台至 Amazon IoT Core – 开启新的智能互联之旅

1. 前言

随着物联网(Internet of Things, IoT)技术的迅速发展,越来越多的智能家居和车联网企业,开始探索和部署 IoT 解决方案,以提升运营效率、增强客户体验。然而,近期市场上部分云服务商陆续宣布关闭或收缩其 IoT 平台服务,给依赖这些平台的客户带来了不小的挑战。面对这一变化,寻找一个稳定可靠且功能强大的替代方案成为了当务之急。

在这样的背景下,Amazon IoT Core 凭借其卓越的性能、丰富的功能以及广泛的物联网云边生态系统支持,成为了众多企业的首选迁移目标。Amazon IoT Core 不仅支持数十亿个设备和数万亿条消息,还提供从设备管理到数据处理的一站式解决方案,帮助企业轻松应对各种复杂的 IoT 应用场景。

本篇博客旨在为有迁移需求的企业提供详细的指南,涵盖从方案选型、制定合适的迁移策略,到实施迁移计划、优化新平台配置的全过程。我们将介绍如何利用 Amazon IoT Core 的各项特性,确保迁移过程平稳过渡,同时最大化新平台带来的价值。

2. 迁移方案

IoT 平台迁移涉及核心业务系统的改造,过程复杂且面临很多挑战,是需要用户综合考虑和详细规划的一个复杂任务。本文将针对客户在 IoT 迁移方案设计中的核心问题,给出解决方案和实现方式。

2.1 云平台架构

典型的物联网架构如下所示。设备通过预先配置的三元组或账号密码进行身份鉴权。上行下行消息的主题需要使用平台定义的属性上报或服务调用等物模型的 MQTT Topic 来实现。后端服务和设备的交互方式有消息转发(AMQP 客户端实现服务端订阅)、云产品流转到数据库,及消息中间件服务等。

Figure 1 待迁移平台的架构

根据新老设备是否同时连接到新平台,迁移架构可以分为两类:

  • 增量迁移
  • 全量迁移

2.1.1 增量迁移

Figure 2 增量迁移的架构

老设备的端侧不做改变,仍然连接到老的云平台。新设备采用新固件方案,连接到 Amazon IoT Core,实现属性上报和下发指令。其中使用的 MQTT Topic 可以参考原有的预留主题来设计。在 AWS 上新建后端服务,用于管理所有 IoT 相关业务。为提高系统可用性和弹性拓展能力,推荐使用 Serverless 属性的相关 AWS 服务来作为云端技术栈;老系统中需要新增 API,便于查询老设备数据、将老设备的连接/状态信息等同步到新后端服务,方便系统的统一维护和管理。用户访问新后端系统的 API 来查询设备属性,再调用相应 API 实现状态查询、发布控制指令。

等待老设备的服务期或者老平台维保期结束,所有设备将全部由新平台来统一管理。

2.1.2 全量迁移

Figure 3 全量迁移的架构

基于 Amazon IoT Device SDK 开发完成新固件后,通过原有物联网平台的 OTA 功能推送给老设备;新固件如果不包含一机一密的证书,第一次上电后通过 Fleet Provisioning 流程,校验设备端 SN 等信息后下发专属设备 X.509 证书。老设备使用证书来连接 Amazon IoT Core,实现 mTLS 双向认证的安全连接。需要将老设备的设备信息和历史数据等迁移到新后端服务的数据库,新系统将会统一维护和管理。

2.2 MQTT 连接的鉴权方式

Amazon IoT Core 支持三种连接协议(MQTT, MQTT over WebSocket, HTTP)和三种鉴权方式(X.509 证书、SigV4 签名机制、自定义鉴权),对应关系如下表所示。

通信协议 支持的 MQTT 功能 鉴权方式
MQTT over WebSocket Publish, Subscribe Signature Version 4
MQTT over WebSocket Publish, Subscribe Custom authentication
MQTT Publish, Subscribe X.509 client certificate
MQTT Publish, Subscribe X.509 client certificate
MQTT Publish, Subscribe Custom authentication
HTTPS Publish only Signature Version 4
HTTPS Publish only X.509 client certificate

物联网系统一般有三类终端需要收发消息:设备端、应用后端、移动端。

  • 设备端:IoT 设备一般处于弱网环境,建议使用原生 MQTT 协议进行连接,有以下三种鉴权方式
    • 使用 X.509 设备证书进行双向校验
    • 使用自定义鉴权方式(即使用账号密码、session token 等方式)
    • 使用 X.509 证书+自定义鉴权双重验证
  • 应用后端:云上环境一般网络状态良好,可以使用标准 MQTT 协议或者 MQTT over WebSocket 协议进行连接
    • 使用 AWS Access Key 和 Secret Key (Signature Version 4) 方式进行鉴权,比如 export 到环境变量中
    • 使用 X.509 证书进行鉴权,将证书文件存放在服务器上
  • 移动端:一般网络状态良好,可以使用标准 MQTT 或者 MQTT over WebSocket 协议进行连接
    • 由于移动端 App 容易被反编译破解,如果使用 X.509 证书,建议不要写入 App 代码中,或直接存放在文件系统中,建议使用 KeyChain 来存放 PCKS#12 证书文件,可以参考 AWS IoT Device SDK Android 示例
    • 移动端一般都需要用户使用账号密码来登陆,因此 MQTT 连接也可以直接复用这些账号密码,使用 Custom Authentication
    • 使用 Amazon STS 服务生成的临时 Access Key 和 Secret Key (Signature Version 4) 方式进行鉴权

以上各种鉴权方式的代码实现将在后续博客中详细展开和演示。

2.3 设备端改造

很多 IoT 客户在原平台设备端都使用了开源 MQTT 库进行连接,例如 Eclipse Paho MQTT C/Java/Python, Eclipse Mosquito, HiveMQ MQTT Client。迁移到 Amazon IoT Core 后,可以继续使用这些开源库。

注:本文将使用 Amazon Cloud9 (Ubuntu Server 22.04 LTS) 作为编译环境来进行演示如何基于开源 MQTT Client 库 (paho.mqtt.c) 安全高效地连接到 IoT Core。

需要用户准备好以下条件:

  • Cloud9 实例(操作系统 Ubuntu Server 22.04 LTS);
  • AWS 账号创建好具备管理员权限的 Access Key、Secret Key;
  • 提前为 IoT Core 配置好 Custom Authorizer,进行账号密码或三元组的验证。

2.3.1 使用 X.509 证书进行 mTLS(双向 TLS)MQTT 连接

请登陆到 Cloud9 进行下面的操作。

# Build paho.mqtt.c
sudo apt-get install build-essential gcc make cmake cmake-gui cmake-curses-gui
sudo apt-get install fakeroot devscripts dh-make lsb-release
sudo apt-get install libssl-dev
sudo apt-get install doxygen graphviz
cd ~/environment
git clone https://github.com/eclipse/paho.mqtt.c
mkdir build.paho
cd build.paho
cmake -DPAHO_WITH_SSL=TRUE -DPAHO_BUILD_DOCUMENTATION=TRUE \
    -DPAHO_BUILD_SAMPLES=TRUE ~/environment/paho.mqtt.c
cmake --build . --target package
cd /home/ubuntu/environment/build.paho/src/samples

# Create IoT X.509 certificate
cd ~
export AWS_ACCESS_KEY_ID=xxxx #填入Access Key
export AWS_SECRET_ACCESS_KEY=xxxxxxx #填入Secret Key
curl -O https://www.amazontrust.com/repository/AmazonRootCA1.pem
aws iot create-keys-and-certificate \
    --certificate-pem-outfile "cert.pem" \
    --public-key-outfile "public.key" \
    --private-key-outfile "private.key"
cp cert.pem ~/environment/build.paho/src/samples/
cp private.key ~/environment/build.paho/src/samples/

# mqtt3.1.1, publish
cd /home/ubuntu/environment/build.paho/src/samples
./paho_cs_pub -c ssl://xxxxx-ats.iot.ap-southeast-1.amazonaws.com:8883 -t test -i test_clientid --trace "protocol" -m "hello!" --cert cert.pem --key private.key
# sample response:
....
Trace : 4, 20241129 071927.089 SSL certificate verification: X509_V_OK
Trace : 4, 20241129 071927.089 SSL connect:SSL negotiation finished successfully
Trace : 4, 20241129 071927.089 peername from X509_check_host is *.iot.ap-southeast-1.amazonaws.com
Trace : 4, 20241129 071927.099 3 test_clientid -> CONNECT version 4 clean: 1 (0)
Trace : 4, 20241129 071927.099 3 test_clientid <- CONNACK rc: 0
Trace : 4, 20241129 071927.099 3 test_clientid -> PUBLISH qos: 0 retained: 0 rc: 0 payload len(6): hello!
Trace : 4, 20241129 071927.099 3 test_clientid -> DISCONNECT (0)
Trace : 4, 20241129 071927.099 SSL alert write:warning:close notify
PowerShell

2.3.2 使用账号密码进行单向 TLS MQTT 连接

# Create IoT Core domain config for custom authentication with username/password    
aws iot create-domain-configuration --region ap-southeast-1     \
    --domain-configuration-name sample_domainConfig_customAuth \
    --service-type DATA   \
    --authentication-type CUSTOM_AUTH   \
    --application-protocol SECURE_MQTT  \
    --authorizer-config defaultAuthorizerName="sample_authorizer",allowAuthorizerOverride=true 
# Response
{
    "domainConfigurationName": "sample_domainConfig_customAuth",
    "domainConfigurationArn": "arn:aws:iot:ap-southeast-1:xxxxxxxxxxxx:domainconfiguration/sample_domainConfig_customAuth/c7dio"
}
# Describe domain config
aws iot describe-domain-configuration --region ap-southeast-1     \
    --domain-configuration-name sample_domainConfig_customAuth    
# Response
{
    "domainConfigurationName": "sample_domainConfig_customAuth",
    "domainConfigurationArn": "arn:aws:iot:ap-southeast-1: xxxxxxxxxxxx:domainconfiguration/sample_domainConfig_customAuth/c7dio",
    "domainName": "xxxxx-ats.iot.ap-southeast-1.amazonaws.com",
    "serverCertificates": [],
    "authorizerConfig": {
        "defaultAuthorizerName": "sample_authorizer",
        "allowAuthorizerOverride": true
    },
    "domainConfigurationStatus": "ENABLED",
    "serviceType": "DATA",
    "domainType": "AWS_MANAGED",
    "lastStatusChangeDate": "2024-11-29T22:55:32.205000+08:00",
    "tlsConfig": {
        "securityPolicy": "IoTSecurityPolicy_TLS13_1_2_2022_10"
    },
    "authenticationType": "CUSTOM_AUTH",
    "applicationProtocol": "SECURE_MQTT"
}

# mqtt3.1.1, publish with username/password
./paho_c_pub -c ssl://xxxxx-ats.iot.ap-southeast-1.amazonaws.com:443 -t test -i test_clientid --trace "protocol" -m "hello!" --username "test" --password "test"
./paho_c_pub -c ssl://xxxxx-ats.iot.ap-southeast-1.amazonaws.com:8883 -t test -i test_clientid --trace "protocol" -m "hello!" --username "test" --password "test"
./paho_c_pub -c ssl://xxxxx-ats.iot.ap-southeast-1.amazonaws.com:8443 -t test -i test_clientid --trace "protocol" -m "hello!" --username "test" --password "test"
# Response:
Trace : 4, 20241129 154040.680 SSL handshake done write:unknown:unknown
Trace : 4, 20241129 154040.680 SSL certificate verification: X509_V_OK
Trace : 4, 20241129 154040.680 SSL connect:SSL negotiation finished successfully
Trace : 4, 20241129 154040.680 peername from X509_check_host is *.iot.ap-southeast-1.amazonaws.com
Trace : 4, 20241129 154040.680 3 test_clientid -> CONNECT version 4 clean: 1 (0)
Trace : 4, 20241129 154040.680 3 test_clientid <- CONNACK rc: 0
Trace : 4, 20241129 154040.813 3 test_clientid -> PUBLISH qos: 0 retained: 0 rc: 0 payload len(6): hello!
Trace : 4, 20241129 154040.813 3 test_clientid -> DISCONNECT (0)
Trace : 4, 20241129 154040.813 SSL alert write:warning:close notify
PowerShell

通过上面示例可以看出,目前通过 IoT Core domain configurations 功能,配置域名后支持 443/8883/8443 任意一个端口进行 MQTT 连接。

2.4 IoT 物模型的构建

原有物联网平台中一般都有定义物模型,包括属性、服务、事件等功能,迁移到 Amazon IoT Core 后,可以结合 MQTT 主题发布订阅、设备影子规则引擎等来实现等效的功能。

2.4.1 物模型-属性(上行)

传感器数据的上报和更新是典型的属性功能。上行的属性数据一般是最大的数据来源,建议使用规则引擎的 Basic Ingest 功能,流转到消息中间件 Amazon Kinesis Data StreamsAmazon Managed Streaming for Apache Kafka 等,再触发 Amazon Lambda 函数批量处理后进入业务系统的数据库 Amazon DynamoDB,典型架构如下所示。

Figure 4 属性上报的架构图

另外,设备的在线离线状态也是典型的属性场景,用户可以直接开启 Fleet Indexing 中的 ThingConnectivityIndexing 功能,通过 API 直接查询设备最新状态。

例如,我们有一台空气净化器(Thing name = myPurifier),每 5 分钟上报 PM2.5/PM10/温度/湿度的数据到云端 IoT 平台。上报到规则引擎的 JSON 数据可以使用如下结构:

{"PM25":34, "PM10":20, "Temperature":25, "Humidity":80, "DeviceTs": 1712988368000}
PowerShell

这些属性也可以直接使用 Device Shadow 设备影子来进行持久化存储,减少后端数据库和计算资源的消耗。上报的影子消息:

{"state":{"reported":{"PM25":34, "PM10":20, "Temperature":25.1, "Humidity":80, "DeviceTs": 1712988368000}}}
PowerShell

2.4.2 物模型-事件(上行)

典型的事件场景包括传感器超阈值的告警、摄像头目标识别结果上报、设备异常工作状态上报等,Amazon IoT Core 的设备影子(Device Shadow)可以帮助客户实现事件信息的持久化存储和联动操作。

具体实现方式:创建一个 Named Shadow (Shadow name = eventsShadow) 用于存放事件,后端服务订阅该影子的 Delta 主题获取新事件的推送。

比如,当 PM2.5 过高时,设备上报的事件消息到影子 topic “$aws/things/myPurifier/shadow/name/eventsShadow/update”,影子的数据格式如下所示:

{"state":{"desired":{"Event": "PM25", "EventTelemetry": {"PM25":34, "PM10":20, "Temperature":25.1, "Humidity":80, "DeviceTs": 1712988368000}}}}
PowerShell

2.4.3 物模型-服务(下行)

典型的服务场景就是给设备下发远程指令,比如后端服务远程控制净化器去切换运行状态。

具体实现方式可以参考 AWS IoT Device Shadow 说明,设备订阅 update/delta 主题,后端服务向 update 主题发送消息,修改 desired.mode 中的自定义字段,比如{”mode”:1},设备收到 delta 消息后执行相应的操作,再上报最新状态到 update 主题修改 reported.mode 即可实现。具体操作可以参考下面 paho.mqtt.c 的指令:

# Publish to shadow update topic to initiate shadow.
./paho_c_pub -c ssl://xxxxx-ats.iot.ap-southeast-1.amazonaws.com:8883 -t '$aws/things/myPurifier/shadow/name/eventsShadow/update' -i pubClient --trace "protocol" --cert cert.pem --key private.key -m '{"state":{"reported":{"mode":1},"desired":{"mode":1}}}'
# Subscribe to shadow update/delta topic, on IoT device
./paho_c_sub -c ssl://xxxxx-ats.iot.ap-southeast-1.amazonaws.com:8883 -i subClient --trace "error" --cert cert.pem --key private.key -q 1 -t '$aws/things/myPurifier/shadow/name/eventsShadow/update/delta' 
# Publish to shadow update topic in new terminal, as a command.
./paho_c_pub -c ssl://xxxxx-ats.iot.ap-southeast-1.amazonaws.com:8883 -t '$aws/things/myPurifier/shadow/name/eventsShadow/update' -i pubClient --trace "protocol" --cert cert.pem --key private.key -m '{"state":{"desired":{"mode":2}}}'
# Subscriber received message as follow:
u-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #21~22.04.1-Ubuntu SMP Thu Nov  7 17:33:30 UTC 2024
Trace : 3, =========================================================
{"version":18,"timestamp":1733708618,"state":{"mode":2},"metadata":{"mode":{"timestamp":1733708618}}}
PowerShell

2.5 成本优化

Amazon IoT Core 计费模式主要分为以下四个部分:连接费用、消息收发、设备影子和注册表,以及规则引擎。其中连接费用为必要项;是否需要对消息收发进行计费取决于用户的场景是否需要通过消息代理进行发布订阅;是否需要应用设备影子和设备注册以及规则引擎取决于用户的场景是否涉及设备注册,请求/响应模式下的设备状态同步,以及是否需要将消息持续流转到亚马逊云中的后端业务。其中消息费用为核心费用,消息收发费用优化可以主要从消息收发频率、计费单位利用以及使用 Basic Ingest 三种方式实施,后续博客将会分享成本优化的细节。

2.6 云端压测

物联网场景下,全链路的压力测试可以帮助开发团队验证系统承载能力,确保平台能够处理预期的设备连接和数据流量,保证高并发情况下的系统稳定性,避免突发流量造成服务中断;识别性能瓶颈,确保在各种负载下的响应速度,预防系统崩溃,为未来成长做好准备;确保数据处理效率,保证实时数据分析和处理的准确性,验证物联网平台的可靠性、可扩展性和实时性能,为用户提供稳定服务。

Amazon IoT Core 作为设备连接层的核心服务,建议模拟突增流量来实现压测验证平台可靠性。灵活使用 AWS 云计算服务可以有效提升压测效率,比如 Amazon Lambda 函数、Amazon EC2 等可以帮助用户短时间内发起海量的 MQTT 连接,具体实现方式将在后续博客中详细介绍。

2.7 总结

物联网平台迁移的整体流程和步骤如下图所示。

Figure 5 物联网平台迁移整体流程

方案评估阶段需要确定好云端接入方案、硬件升级方案、数据流转方案等。无论是从云厂商托管 IoT 服务迁移、从基于开源的自建方案迁移,还是从企业版 MQTT Broker 服务迁移,本文讨论的内容都可以作为指导和参考。物联网平台迁移涉及面广,需要用户综合考量,希望本文对您制定 IoT 平台迁移方案有所启发。

本篇作者

黄梓航

亚马逊云科技解决方案架构师,负责亚马逊云科技 IoT 相关服务的技术推广和方案设计。拥有多年车联网、智能家居、工业互联等物联网领域经验,曾在博世和阿里云技术岗位任职多年。目前致力于物联网、边缘计算、大数据、人工智能和机器学习等跨学科融合方案的研究。

曹阳

亚马逊云科技解决方案架构师,负责基于亚马逊云科技云计算方案的架构咨询与设计,同时致力于亚马逊云科技在各行业中的应用与推广,目前侧重于移动应用以及物联网领域的研究。

郑辉

亚马逊云科技解决方案架构师,负责基于亚马逊云计算方案架构的咨询和设计,在国内推广亚马逊云平台技术和各种解决方案。业余时间,他喜欢为自己和家人做美食。

李宛真

亚马逊云科技技术客户经理,主要负责企业级客户的安全合规、成本管理和技术支持等工作。目前专注于协助客户落地在亚马逊云的安全合规工作。在加入亚马逊云科技前拥有丰富的视频云行业(如 CDN、直播、对像存储等)的技术支持经验。