边缘计算这两年很火,随着5G和物联网的发展,越来越多的公司开始在边缘端部署计算能力,把数据处理从云端下沉到离数据源更近的地方,降低延迟、节省带宽、提升响应速度。概念听起来很美好,但真正做起来才发现,边缘计算的水很深,从架构设计到部署运维,到处都是坑。

最近在项目里做了一个边缘计算的应用,场景是在工厂的生产线上部署边缘节点,实时处理传感器数据,做质量检测和异常预警。从架构设计到设备选型,从开发调试到部署运维,前前后后搞了几个月,踩了不少坑,也总结了一些经验。今天把这些坑整理出来,分享给同样在做边缘计算或者准备做边缘计算的朋友,希望大家能少走弯路。

先说明一下,我们的项目用的是通用的x86边缘网关 + Docker容器化部署,云端用的是阿里云,边缘和云端之间用MQTT做消息通信。不同的技术栈可能会有不同的坑,但思路是相通的。

一、网络相关的坑

边缘计算最大的特点就是边缘节点分布在各个地方,网络环境复杂多变,网络相关的问题是最常见、也最头疼的。

坑1:网络不稳定,连接经常断

这是边缘计算最常见的坑。边缘节点部署在工厂、仓库、户外等各种环境,网络条件千差万别,有的用有线,有的用WiFi,有的用4G,网络质量参差不齐,经常出现网络抖动、延迟高、甚至断网的情况。

刚开始我们没太当回事,觉得网络断了重连就行。但实际跑起来才发现,网络断了之后,边缘节点上的应用会出现各种问题:消息发不出去、数据丢失、任务卡住、甚至整个应用崩溃。而且网络恢复之后,数据怎么同步、任务怎么恢复,都是问题。

解决方法是:

  • 应用层要做网络容错:不要假设网络一直是通的,所有的网络请求都要加重试和超时机制,失败了要能重试,重试失败要能降级处理。
  • 数据要本地缓存:网络断了的时候,数据先存在本地,等网络恢复了再同步到云端。我们用了SQLite做本地存储,消息队列用了EMQX的本地队列,网络断了的时候数据先存本地,恢复了再同步。
  • 心跳和重连机制:边缘节点和云端之间要用心跳检测连接状态,断开了要自动重连,重连之后要做数据同步和状态恢复。
  • 关键业务要能离线运行:边缘计算的优势之一就是能离线运行,不要把所有逻辑都依赖云端。关键的业务逻辑要能在边缘端独立运行,网络断了也能正常工作,网络恢复了再同步数据。

坑2:NAT穿透,云端无法主动访问边缘节点

大部分边缘节点都在局域网内, behind NAT,云端无法主动访问边缘节点,只能边缘节点主动连接云端。这就导致很多需要云端主动下发的操作(比如远程配置、远程升级、远程调试)变得很麻烦。

刚开始我们想让云端直接调用边缘节点的HTTP接口,结果发现根本连不上,因为边缘节点没有公网IP。后来想了几个方案:

  • 方案1:边缘节点主动轮询云端:边缘节点每隔一段时间去云端问有没有新的指令,有就拉下来执行。这个方案简单,但实时性差,而且浪费带宽。
  • 方案2:用长连接,云端通过长连接下发指令:边缘节点主动和云端建立长连接(比如WebSocket、MQTT),云端通过长连接给边缘节点下发指令。这个方案实时性好,我们最终用的就是这个方案,用MQTT的主题来做指令下发。
  • 方案3:用内网穿透工具:比如frp、ngrok,把边缘节点的端口映射到公网,云端就能访问了。这个方案适合调试用,但生产环境不推荐,因为安全性和稳定性都有问题。

坑3:带宽有限,数据传输成本高

边缘节点很多用的是4G或者物联网卡,带宽有限,流量费也不便宜。如果把所有原始数据都传到云端,带宽和流量成本会很高,而且延迟也大。

这其实就是边缘计算要解决的问题:在边缘端做数据处理和过滤,只把有价值的数据传到云端。但实际做的时候,很容易忽略这个问题,把大量原始数据传到云端,导致带宽成本飙升。

我们的做法是:

  • 边缘端做数据预处理:在边缘端做数据清洗、过滤、聚合,只把异常数据和统计结果传到云端,原始数据存在本地或者直接丢弃。
  • 数据压缩:传输的数据做压缩,比如用gzip或者protobuf,减少数据体积。
  • 分级传输:不同优先级的数据用不同的传输策略,关键数据实时传输,非关键数据批量传输或者延迟传输。
  • 监控带宽使用:监控每个边缘节点的带宽使用情况,发现异常及时排查,避免因为某个节点传输大量数据导致成本飙升。

二、设备相关的坑

边缘计算的设备多种多样,从高端的边缘服务器到低端的嵌入式设备,性能和资源差别很大,设备相关的坑也不少。

坑4:边缘设备性能有限,应用跑不起来

刚开始我们用了比较低端的边缘网关,配置是双核CPU、2G内存,想着只是处理传感器数据,应该够用。结果把应用部署上去才发现,根本跑不起来,CPU和内存常年100%,应用卡顿严重,甚至经常OOM被系统杀掉。

后来分析原因,主要是几个问题:

  • 我们的应用用了Java,JVM本身就吃内存,2G内存根本不够用。
  • 数据处理用了比较重的算法,CPU占用高。
  • 同时跑了好几个容器,每个容器都占资源,加起来就超了。

解决方法:

  • 根据应用需求选设备:不要盲目追求便宜,要根据应用的资源需求来选设备。如果用Java或者Python这种比较吃资源的语言,至少要4G内存起步;如果用Go或者C++这种轻量的,可以用配置低一点的设备。
  • 优化应用资源占用:对应用做性能优化,减少内存和CPU占用。比如JVM调优、用更轻量的算法、减少不必要的并发、用连接池等。
  • 合理规划容器资源:用Docker的时候,要给每个容器设置CPU和内存限制,避免某个容器占用太多资源影响其他容器。同时也要合理规划在一个设备上跑多少个容器,不要超卖。
  • 考虑用轻量级语言和框架:边缘端资源有限,尽量用Go、Rust、C++这种轻量高效的语言,以及轻量级的框架,避免用Java EE这种重量级的技术栈。

坑5:设备环境不统一,部署和调试困难

边缘节点的设备型号、操作系统、内核版本、硬件架构可能都不一样,有的是x86,有的是ARM,有的是Ubuntu,有的是CentOS,有的甚至是定制的嵌入式系统。环境不统一,导致应用部署和调试很困难,经常出现"在我这能跑,在那跑不起来"的问题。

解决方法:

  • 容器化部署:用Docker把应用和依赖打包成镜像,屏蔽底层环境的差异。只要设备上能跑Docker,应用就能跑,不用关心底层是什么系统。这是我们最主要的解决方案,容器化大大降低了部署的复杂度。
  • 统一基础镜像:所有应用的Docker镜像都基于同一个基础镜像构建,保证运行时环境一致。基础镜像里包含了统一的操作系统、运行时、依赖库等。
  • 多架构镜像构建:如果设备有x86和ARM两种架构,要用Docker的buildx构建多架构镜像,或者分别构建不同架构的镜像,部署的时候根据设备架构拉取对应的镜像。
  • 设备标准化:在项目初期就尽量统一设备型号和系统版本,不要什么设备都用。统一的环境能大大减少部署和运维的复杂度。如果实在无法统一,至少要把设备分成几类,每类用统一的配置。

坑6:设备断电和异常重启,数据丢失

边缘设备的运行环境往往比较恶劣,可能会突然断电、系统崩溃、硬件故障,导致设备异常重启。如果应用没有做好持久化和容错,就会丢失数据,甚至损坏文件。

我们就遇到过一次,工厂突然停电,边缘网关断电重启,结果因为SQLite正在写数据的时候断电,数据库文件损坏了,丢失了好几个小时的数据。

解决方法:

  • 数据要及时持久化:重要的数据要及时写入磁盘,不要只存在内存里。写数据库的时候要用事务,保证数据的一致性。
  • 用支持崩溃恢复的存储:SQLite要开启WAL模式,提高并发性能和崩溃恢复能力。或者用更健壮的数据库,比如RocksDB、LevelDB。
  • 定期备份数据:重要的数据要定期备份,比如每天备份一次,备份文件可以存在本地,也可以同步到云端。万一数据损坏了,可以从备份恢复。
  • 应用要支持幂等和断点续传:数据同步的时候要支持幂等,重复传输不会导致数据重复或错误。还要支持断点续传,传输中断了可以从断点继续,不用从头开始。
  • 考虑用UPS:对重要的边缘节点,可以配一个小型UPS,防止突然断电。虽然不能完全避免断电,但能给设备一点时间做优雅关闭,减少数据损坏的概率。

三、数据相关的坑

边缘计算的核心是数据处理,数据相关的坑也很多。

坑7:数据一致性,边缘和云端数据不同步

边缘计算是分布式架构,数据同时存在于边缘端和云端,很容易出现数据不一致的问题。比如边缘端修改了数据,但还没同步到云端,云端又修改了同一条数据,就会出现冲突。

刚开始我们没太在意数据一致性的问题,觉得最后同步到云端就行。结果跑了一段时间,发现数据对不上,边缘端和云端的数据有差异,而且不知道哪个是对的,排查起来很头疼。

解决方法:

  • 明确数据的主从关系:哪些数据以边缘端为准,哪些数据以云端为准,要明确。比如传感器原始数据以边缘端为准,配置信息以云端为准。明确了主从关系,冲突的时候就知道以谁为准。
  • 用时间戳和版本号解决冲突:每条数据都带时间戳和版本号,同步的时候根据时间戳和版本号来判断哪个是最新的,发生冲突的时候按规则合并或者保留最新的。
  • 最终一致性即可,不要强求强一致性:边缘计算的场景下,强一致性很难实现,成本也很高。大部分场景下,最终一致性就够了,只要数据最终能同步一致,短暂的不一致是可以接受的。
  • 监控数据同步状态:监控边缘和云端的数据同步情况,发现同步延迟或者数据不一致及时告警,人工介入处理。

坑8:数据格式不统一,解析困难

边缘节点接入的设备多种多样,不同的传感器、不同的设备厂商,数据格式可能都不一样,有的用JSON,有的用二进制,有的用Modbus,有的用自定义协议。数据格式不统一,导致解析和处理很困难。

我们的项目里就接入了好几种传感器,每种的数据格式都不一样,刚开始写了好几个解析函数,代码又乱又难维护,加一种新传感器就要改很多代码。

解决方法:

  • 设计统一的数据模型:在边缘端设计一个统一的数据模型,不管底层设备是什么格式,都转换成统一的格式再处理和上传。比如统一成包含设备ID、时间戳、数据类型、数据值的JSON格式。
  • 用适配器模式:每种设备写一个适配器,把设备的原始数据转换成统一格式。新增设备的时候只要加一个适配器,不用改核心逻辑。
  • 用标准协议:尽量用标准的物联网协议,比如MQTT、CoAP、Modbus、OPC UA,不要用太多自定义协议。标准协议有成熟的库和工具,开发和维护成本低。
  • 数据校验:接入的数据要做校验,检查格式是否正确、数值是否在合理范围内,避免脏数据进入系统。

四、安全相关的坑

边缘节点分布在各个地方,物理上不安全,网络环境也复杂,安全问题很重要,但也很容易被忽略。

坑9:边缘节点物理不安全,容易被篡改

边缘节点部署在工厂、仓库、户外等地方,物理上不安全,任何人都可能接触到设备,可能被篡改、被偷、被插入恶意设备。刚开始我们没太在意物理安全,觉得没人会去动一个网关,结果有一次现场的工人不小心把网关恢复出厂设置了,导致整个节点失联了好几天。

解决方法:

  • 设备锁和机箱锁:把边缘设备放在锁着的机箱里,或者用设备锁固定,防止被随意搬动和篡改。
  • BIOS和系统密码:设置BIOS密码和系统登录密码,防止别人随意进入系统修改配置。
  • 应用签名和校验:应用的Docker镜像要做签名,部署的时候校验签名,防止被篡改的镜像运行。
  • 敏感数据加密:设备上的敏感数据(比如密钥、证书、配置)要加密存储,防止设备被偷之后数据泄露。
  • 远程监控设备状态:监控设备的在线状态、系统配置、运行进程,发现异常(比如配置被改了、多了陌生进程)及时告警。

坑10:网络通信不安全,数据被窃听或篡改

边缘节点和云端之间的通信,很多时候走的是公共网络,如果不加密,数据可能被窃听或篡改。刚开始我们为了省事,MQTT连接没加密,用的是明文传输,后来安全审计的时候被指出了这个问题,才改成了TLS加密。

解决方法:

  • 通信加密:边缘和云端之间的所有通信都要用TLS加密,不管是MQTT、HTTP还是其他协议,都不要明文传输。
  • 双向认证:用TLS双向认证,云端验证边缘节点的证书,边缘节点也验证云端的证书,防止伪造的节点接入。
  • 密钥和证书管理:每个边缘节点用独立的证书和密钥,不要共用。证书要有过期时间,定期轮换。密钥和证书要安全存储,不要硬编码在代码里。
  • API鉴权:云端的API要做鉴权,用API Key、Token或者证书,不要让未授权的客户端访问。
  • 定期安全审计:定期做安全审计,检查有没有安全漏洞,及时修复。

五、运维相关的坑

边缘节点数量多、分布广,运维起来比集中式的云端服务困难得多。

坑11:远程升级困难,升级失败导致设备变砖

应用需要定期升级,但边缘节点分布在各个地方,不可能每次都派人去现场升级,必须支持远程升级。但远程升级有风险,如果升级过程中断网或者断电,可能导致升级失败,设备变砖,只能派人去现场修复。

我们就遇到过一次,远程升级的时候有几个节点断网了,升级到一半失败了,结果应用起不来,节点失联,最后只能派人去现场一个个修复,花了很多时间和人力。

解决方法:

  • A/B分区升级:设备上分A和B两个分区,当前运行在A分区,升级的时候写B分区,升级成功了切换到B分区启动,失败了还能从A分区启动,不会变砖。这是最可靠的方案,但需要设备支持。
  • 容器化升级:用Docker的话,升级就是拉新镜像、停旧容器、启新容器,过程比较简单。如果新容器启动失败,可以回滚到旧镜像。但要注意如果拉镜像的时候断网,旧容器还在运行,不会影响业务。
  • 升级前做检查:升级前检查设备状态,比如网络是否正常、磁盘空间是否够、当前应用是否正常,条件满足了再升级。
  • 灰度升级:不要一次性升级所有节点,先升级一小部分,观察没问题了再逐步扩大范围。万一升级有问题,影响范围也有限。
  • 升级失败自动回滚:如果新应用启动失败或者健康检查不通过,自动回滚到旧版本,保证业务不中断。
  • 升级进度上报:升级过程中把进度上报到云端,运维人员能看到每个节点的升级状态,发现失败的及时处理。

坑12:监控和日志不完善,出了问题无法排查

边缘节点分布在各个地方,出了问题如果没有完善的监控和日志,根本不知道发生了什么,也无法排查。刚开始我们的监控很简单,只看节点在不在线,结果有一次节点在线但应用不正常,数据不往上发了,过了好几天才发现,排查的时候也没有足够的日志,不知道是什么原因。

解决方法:

  • 完善的监控指标:监控每个边缘节点的系统指标(CPU、内存、磁盘、网络)、应用指标(运行状态、处理数据量、错误率、延迟)、业务指标(数据上传量、异常检测数量等),全方位监控节点状态。
  • 集中式日志收集:边缘节点的日志要收集到云端,用ELK或者Loki之类的工具做集中式存储和查询。出了问题能在云端直接查日志,不用登录到设备上。日志要带节点ID、时间戳、日志级别等信息,方便筛选和查询。
  • 告警机制:设置合理的告警规则,节点离线、应用异常、资源使用率过高、数据同步延迟等,都要及时告警,通知运维人员处理。不要等问题严重了才发现。
  • 远程调试能力:支持远程登录到边缘节点(比如SSH或者WebSocket终端),出了问题能远程排查,不用每次都派人去现场。但要注意安全,远程登录要做鉴权和审计。
  • 设备健康检查:定期做设备健康检查,检查硬件状态、系统状态、应用状态,发现潜在问题提前处理,不要等设备挂了才发现。

六、一些建议和心得

最后,总结一些做边缘计算的建议和心得:

  1. 不要为了边缘计算而边缘计算。边缘计算不是银弹,不是所有场景都适合。先想清楚你的场景是不是真的需要边缘计算,是不是有低延迟、离线运行、带宽成本的需求。如果没有这些需求,集中式的云端架构可能更简单、更可靠。
  1. 从简单的场景开始,逐步迭代。不要一开始就搞很复杂的边缘计算架构,先从一个简单的场景、几个节点开始,验证技术方案和业务价值,跑通了再逐步扩大规模和复杂度。
  1. 重视容错和降级。边缘环境复杂多变,网络会断、设备会挂、数据会丢,应用一定要做好容错和降级,不能假设环境是理想的。关键业务要能离线运行,非关键业务出问题了要能降级,不要因为一个小问题导致整个系统崩溃。
  1. 安全从一开始就要考虑。不要等系统做完了再补安全,安全要从架构设计阶段就考虑进去。通信加密、设备认证、数据加密、访问控制,这些都要在一开始就做好,后面再补成本很高。
  1. 运维和部署要自动化。边缘节点数量多、分布广,靠人工运维是不现实的,一定要自动化。自动部署、自动升级、自动监控、自动告警、自动恢复,能自动化的都自动化,减少人工干预。
  1. 选择成熟的技术和工具。边缘计算还在发展中,很多技术和工具还不成熟,尽量选择成熟的、社区活跃的技术和工具,不要用太新太冷门的,否则出了问题没人帮你,自己也很难解决。

七、写在最后

边缘计算是一个很有前景的方向,随着5G和物联网的发展,会有越来越多的应用场景。但它也是一个很有挑战的方向,涉及到网络、设备、数据、安全、运维等多个方面,比集中式的云端应用复杂得多,坑也多得多。

这篇文章整理了我在实际项目中踩过的一些坑,可能不够全面,也可能有不对的地方,欢迎大家指正。每个项目的场景和技术栈都不一样,遇到的坑也会不一样,但核心的原则是相通的:重视容错、重视安全、重视运维、从简单开始、逐步迭代。

希望这篇文章能给正在做边缘计算或者准备做边缘计算的朋友一些帮助,也希望大家都能少踩坑、多成事,把边缘计算的项目做好。