背景

公司战略调整,业务需从 AWS 迁移至 GCP。受限于客观条件,需在三周内独立完成。

为什么只有我一个人?

  • 其他成员正在跟进定位器上线项目,有同事远赴欧洲现场测试,需远程对接,无法抽身

  • 我本身承担架构、安全、运维、核心代码迭代四重角色,项目从0开始亲手迭代了7年

  • 整个项目,只有我最熟悉所有细节,在零预演的约束下,除了测试,其他人只会帮倒忙

不是团队不想帮,是确实帮不上。这个迁移,只能我来。

真实工作路线

时间事件
3月底收到迁移命令,开始推演方案
4月初被视觉AI紧急任务打断,迁移暂停
5月8日AI demo 完成,接到“5月31日前必须完成欧美双节点迁移”的死命令
5月9日 - 5月30日实际迁移窗口(零预演,边干边切
5月31日欧美双节点迁移完成

范围

  • 欧洲节点:万级在线设备,仅服务欧洲地区
  • 北美节点:万级 TCP 长连接 + 万级短连接设备,服务除中国和欧洲外的全球地区
  • 中国节点:设备量约北美节点的两倍,仅服务中国地区

本次仅迁移欧美节点。

目标

业务平稳过渡,用户无感。

整体技术架构

终端层 → TCP 长连接设备(自定义协议)

接入层 → 基于 Netty 的网关集群,按区域部署

业务层 → 设备管理 / 指令下发 / 权限 / 调度

数据与消息层 → MySQL(数据存储)、RocketMQ(异步消息)、Redis(缓存)、MinIO(文件存储,原 FastDFS,因视觉 AI 升级)—— 所有组件容器化升级

用户层 → HTTP 短连接

通信链路

  • 场景一:用户与设备在同一区域(同节点)

    1. 下行控制链路(用户 App 下发设备指令)

    用户 App → 业务网关 → 设备业务服务(请求挂起阻塞)→ MQ 流转 → 设备网关 → IoT 设备执行 → 结果回传 → 设备网关回写 MQ → 业务服务唤醒阻塞请求 → 最终结果原路返回至用户 App

    关键特征: 请求挂起阻塞,等待设备响应后才返回,实现同步控制效果。

    2. 上行上报链路(设备主动上报状态、数据、告警)

    IoT 设备主动上报 → 设备网关 → MQ 流转 → 后端业务服务消费处理核心逻辑 → 重要告警、状态变更调用第三方推送直达用户 App → 非核心数据规整归档 → 回写 MQ → 设备网关 → IoT 设备

    关键特征: 重要数据实时推送,非核心数据异步归档,链路闭环(MQ 回写用于后续下行动作)。

  • 场景二: 用户出差,人在欧洲,设备在中国

    1. 下行控制链路(用户 App 下发设备指令)

    用户 App(欧洲)→ 业务网关(欧洲)→ 本地调度服务 → 数据中心(跨境寻址路由)→ 业务网关(中国)→ 业务服务下发指令 → MQ 流转 → 设备网关(中国)→ 设备执行(中国)→ 结果回传 → 原路返回 → 用户 App(欧洲)

    2. 上行上报链路(设备主动上报状态、数据、告警): 与场景一上行上报链路一致。

    关键特征: 跨境寻址路由——根据用户账号归属地,将请求路由到正确的区域网关,而非就近处理。

  • 场景三: 设备第一网关连接失败,自动切换至第二网关, 导致用户在中国,设备连接了欧洲设备网关

    1. 下行控制链路(用户 App 下发设备指令)

    用户 App(中国)→ 业务网关(中国)→ 设备业务服务(请求挂起阻塞,发现设备异地上线)→ HTTP → 本地调度服务 → 中转 → 数据中心(跨境寻址路由)→ 中转 → 设备网关(欧洲)→ IoT 设备 → 结果回传 → 原路返回 → 用户 App(中国)

    2. 上行上报链路(设备主动上报状态、数据、告警)

    IoT 设备(欧洲)→ 设备网关(欧洲)→ HTTP → 本地调度服务 → 中转 → 数据中心(跨境寻址路由)→ 中转 → 设备归属区域设备网关(中国)→ 请求透传 → 业务服务处理 → 重要告警、状态变更调用第三方推送直达用户 App(中国)→ 非核心数据规整归档 → 结果回传 → 原路返回 → IoT 设备(欧洲)

    关键特征:

    网关容灾:设备自动切换至欧洲网关,数据经跨境寻址路由至中国归属网关,经 HTTP 透传由业务服务处理。重要数据实时推送用户,非核心数据归档后原路返回设备。

  • 场景四:用户与设备同时异地接入(设备和用户归属中国,用户出差美国,设备欧洲接入)

    1. 下行控制链路(用户 App 下发设备指令)

    用户 App(美国)→ 业务网关(美国)→ HTTP → 本地调度服务 → 数据中心(跨境寻址路由)→ 用户账号归属区域业务网关(中国)→ 业务设备服务处理(请求挂起阻塞,发现设备异地上线)→ HTTP → 本地调度服务 → 数据中心(跨境寻址路由)→ 设备网关(欧洲)→ IoT 设备 → 结果回传 → 原路返回 → 用户 App(美国)

    2. 上行上报链路(设备主动上报状态、数据、告警): 与场景三上行上报链路一致。

    关键特征:

    • 双重跨境寻址:下行指令需经过两次跨境路由——先根据用户账号归属(中国),再根据设备实际接入点(欧洲)

    • 归属网关是唯一枢纽:无论用户和设备在哪里,账号归属网关(中国)始终是逻辑中心,所有请求必须经它中转

    • 路径最长,延迟最高:相比场景二(单方异地)增加一次跨境往返,是四种场景中通信路径最长的

设计根源:欧洲数据不出欧洲

上述四种场景的复杂度,根源在于一条硬性约束:欧洲用户和设备的数据不能离开欧洲(GDPR / 数据本地化要求)。

跨云迁移主要难点

  1. RocketMQ 内网 IP 问题
    六年前部署时 Broker 配了内网 IP,导致跨云迁移后新环境无法直接访问旧 MQ 集群。

  2. 设备固化域名解析 IP
    早期合作方未按规范开发,部分设备配网时将域名解析为 IP 并固化到本地缓存,导致迁移后仍直连旧网关。

  3. APP 与设备跨云时空割裂
    迁移过程中,用户 App 已切换至新云(GCP),但设备仍连接旧云(AWS),导致指令无法送达或响应错乱。

  4. 数据库连接池切换时的脏数据问题
    迁移最后一步,将应用的数据源连接池从 AWS 数据库切换到 GCP 数据库。切换不是瞬间完成的——旧连接池还在处理未完成的事务,新连接池已经开始写入,极易产生脏数据。
    一个人运维的困境: 没有团队兜底,压力巨大。

  5. 全球跨洲际路由调度难题
    迁移涉及欧美双节点,设备、用户、归属网关分布在三大洲。切换时不仅要保证单节点内部一致,还要保证跨洲路由不中断。

  6. 迁移期间发现黑客攻击
    迁移窗口期,系统同时处于新旧两套环境并行运行的状态,暴露面翻倍。就在这个时候,发现了异常的跨境请求——有人在试探跨洲路由的边界。

迁移结果

欧洲节点: 用户量较少,作为首个攻克目标。由于没有预演,过程曲折,各种意料之外的问题接踵而至,好在最后有惊无险。

北美节点: 全盘复用欧洲节点的迁移流程,过程顺利。

结语: 7年前亲手创建,7年后亲手删除

在这里插入图片描述

上图为迁移最后一步:删除 AWS 欧美节点的服务器。Zabbix agent 不可用的告警,是这些机器关机前的最后心跳。

更多推荐