【架构案例】支持 6 大厂商的安防集成平台:8000 设备、1000 并发、双部署的设计取舍
📐 本文为架构设计案例研究
案例脱胎于一份真实的海外 B2B 安防项目需求文档(客户名已脱敏为”某海外安防集成商”)。文中涉及的设备规模、协议要求、技术决策均来自原项目,平台本身仍在迭代中。
阅读对象:做 IoT / 安防 / 多协议集成平台的后端架构师。
一、项目背景:一份”什么都要”的客户需求
今年早些时候,一家海外安防集成商发来需求文档,要做一个 集中式安防管理平台。客户原话一句话概括:
‘我们要一个 Linux 上跑的服务,能对接 6 家厂商的设备,能本地部署也能上云,能按月收钱。’
这种”什么都要”的需求,在 B2B 项目里很常见,但落到架构上意味着 每个”要”字背后都是一道工程难题。
需求拆开后,规模是这样的:
加上 6 家厂商的协议都要求”完整支持、不能有偏差”——架构挑战比单一协议集成大得多。
二、第一个决策:协议抽象层(Vendor Adapter Pattern)
6 家厂商的协议特性差异巨大:
关键决策 :不直接让业务层调各家 SDK,而是引入 协议适配层(Vendor Adapter)。
┌──────────────────────────────────────────┐
│ 业务层(事件处理 / 设备管理)│
└─────────────┬────────────────────────────┘
│ 统一接口
┌─────────────▼────────────────────────────┐
│ 协议抽象层(Adapter Interface)│
│ DeviceAdapter | EventAdapter | Stream… │
└─┬────┬────┬────┬────┬────┬───────────────┘
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
Tuya TS Sunell Onvif AOPU SIP
Adapter
带来的好处:– 业务层只调 DeviceAdapter.discover()、EventAdapter.subscribe(),不关心底层是 MQTT 还是私有 TCP – 新增厂商时只需加一个 Adapter,不动业务代码 – 单元测试可对 Adapter 做 Mock,业务逻辑和协议解耦
代价:– 抽象层设计要稳,错一个接口要全改 – 调试时多一层,定位问题稍慢 – 部分厂商特性(如 Tuya 的影子设备、AOPU 的批量打卡)适配时容易丢失
经验 :抽象层是必须做的,问题是 抽象到什么粒度。本项目最终把 Adapter 拆成 4 类(Device / Event / Stream / Control),没再往下拆——再细就是过度设计了。
三、第二个决策:消息总线(事件统一入口)
6 家厂商的事件格式天差地别:
-
Tuya:JSON,MQTT 推送
-
TS:二进制,自定义格式
-
Sunell:HTTP 回调 + 报警编码
-
Onvif:WS-BaseNotification,XML
-
AOPU:TCP 私有协议
-
SIP:SIP 消息 + 扩展头
如果业务层每接一个厂商就要适配一种事件格式,几个月后就是无底洞。
关键决策 :所有厂商事件走 统一事件总线(本项目用 Redis Streams + Kafka 镜像),事件格式统一为内部 JSON Schema。
{
"event_id": "uuid",
"vendor": "tuya",
"device_id": "abc-123",
"event_type": "motion_detected",
"timestamp": 1717300000,
"raw": {/* 厂商原始 payload */},
"normalized": {/* 归一化字段 */}
}
事件从厂商 → Adapter → 归一化 → 总线 → 业务消费,整个链路里 Adapter 是唯一”翻译”。
带来的好处:– 业务侧订阅 motion_detected 就行,不用管是哪个厂商 – 离线 / 重连 / 丢包都由总线兜底 – 后期加”事件规则引擎”很自然(订阅总线,落地规则)
代价:– 总线本身要保证高可用——Redis Streams 集群 + Kafka 双写 – 归一化字段要提前定好,后期加字段很麻烦 – 调试链路长(Adapter → Bus → Consumer),trace 必须打全
经验 :事件归一化的 字段表是项目里最重要的一份文档。建议在 Adapter 写第一行业务代码之前就敲定,否则后期改字段 = 改全链路。
四、第三个决策:双部署模式(本地 + 云端)
客户要求 同时支持本地部署和云端部署。这两者的运维、安全、商业模式完全不同:
关键决策 : 同一套代码、同一份二进制,通过环境变量和 License 切换模式。
Platform Binary
│
├── DEPLOY_MODE=onprem → License 本地激活、设备直连、单机 / 集群
└── DEPLOY_MODE=cloud → 多租户隔离、设备走云端、计费模块
代码层面做这些抽象:– DeploymentContext:根据模式决定是否启用多租户、是否走云端 API、是否启用量控制 – LicenseManager:本地模式读本地文件,云端模式读中央授权服务 – DeviceConnector:本地模式直连设备内网,云端模式通过 VPN/ 反向通道
带来的好处:– 代码库统一,Bug 修一次两边受益 – 客户从本地迁移到云端,技术路径平滑 – License 系统天然支持商业模式
代价:– 抽象层要照顾两种模式的边界,复杂度上去了 – 本地部署的”极简安装”诉求(客户 IT 水平参差)和云端的”高可用”诉求在部署脚本上要分开写 – 安全模型不同:本地模式重边界防护,云端模式重身份认证
经验 :双部署模式 不省钱,反而要花更多精力在抽象设计上。但对 B2B 安防这类强本地需求 + 弱云习惯的行业,这笔钱必须花。
五、第四个决策:License / 授权系统
6 个模块(Tuya / TS / Sunell / Onvif / AOPU / SIP),客户要能 按模块激活 / 停用。这是商业模式的核心。
License 模型:
License 校验点:1. 启动时 → 验证 License 合法性 2. 设备注册时 → 检查 device_quota 3. 用户登录时 → 检查 user_quota 4. 模块调用时 → 检查 modules 列表 5. 后台心跳 → 云端模式定期回传使用量
带来的好处:– 客户按需付费,平台方按用量收费 – 模块隔离:未授权模块不加载,攻击面小 – 升级 / 续费路径清晰
代价:– 离线 License 校验要做加密签名 + 防篡改 – 灰度 / 试用支持要做时间衰减 License – License 服务本身是高可用目标,不能挂
经验 :License 系统建议 第一天就做,别等产品上线后补。补的成本是开发初期的 3-5 倍。
六、关键架构图
下面是平台文档系统的截图(项目实际界面,已脱敏),左侧导航、右侧内容,整体走的是开源 Wiki 风格(具体 Wiki 工具不在本文讨论范围):

整个平台的逻辑架构(按层划分):
┌─────────────────────────────────────────────────┐
│ Web 控制台(Vue/React)│
├─────────────────────────────────────────────────┤
│ API Gateway(认证、限流、路由)│
├─────────────────────────────────────────────────┤
│ 业务服务层 │
│ ├─ DeviceService 设备管理 │
│ ├─ EventService 事件处理 │
│ ├─ VideoService 视频点播 / 直播 │
│ ├─ AccessService 门禁 / 考勤 │
│ ├─ BillingService 计费 / 订阅 │
│ └─ LicenseService 授权管理 │
├─────────────────────────────────────────────────┤
│ 协议抽象层(Adapter)│
│ Tuya TS Sunell Onvif AOPU SIP │
├─────────────────────────────────────────────────┤
│ 消息总线(Redis Streams + Kafka 镜像)│
├─────────────────────────────────────────────────┤
│ 存储层 │
│ ├─ PostgreSQL(业务数据)│
│ ├─ TimescaleDB(事件时序)│
│ ├─ MinIO(视频 / 录像)│
│ └─ Redis(缓存 / 会话 /Quota)│
├─────────────────────────────────────────────────┤
│ 基础设施 │
│ ├─ 部署模式切换(onprem / cloud)│
│ ├─ License 校验 │
│ └─ 监控 / 日志 / 审计 │
└─────────────────────────────────────────────────┘
七、几个非显然的工程坑
写下来给后面做同类项目的人:
坑 1:流媒体是另一个宇宙
摄像头音视频流(RTSP / GB28181 / WebRTC)跟”普通业务系统”完全两个领域。流媒体服务器(SRS / ZLMediaKit / mediasoup)的选型、CDN 转发、录像存储、回放协议——这部分预算要单独算,不能套在普通后端的人月里。
坑 2:海外网络的合规和延迟
客户在海外,平台如果部署在中国大陆,海外访问延迟 + 合规问题会拖死项目。要么平台方有海外节点,要么客户接受”够用就行”的网络质量。
坑 3:6 厂商的设备发现协议完全不一样
-
Tuya 走云端 API
-
Onvif 走组播探测
-
AOPU 是私有广播
-
SIP 有自己的注册机制
没有”统一的设备发现”。这一层要么各家自己实现,要么用”手工录入 + 辅助探测”的混合方案。本项目选了后者。
坑 4:License 防破解是持续战
License 校验做完只是开始。客户会反编译、Patch、二次分发。建议:– License 校验分散到多个关键路径 – 关键模块编译成 native(Go/Rust)而不是脚本 – 云端模式有”心跳回收”机制
坑 5:客户改需求
B2B 项目里,需求变更是常态。架构上要留好扩展点:插件化 Adapter、可配置事件规则、可热插拔的模块。但 别为”未来可能的需求”过度设计——客户最常改的,是他自己也没想清楚的需求。
八、案例总结
这个项目在做什么:– 一个 B2B 安防 SaaS 平台 – 6 大厂商、8000+ 设备、1000 并发 – 本地 + 云端双部署、模块化 License
核心架构决策:1. Vendor Adapter 抽象层 2. 统一事件总线 + 归一化 Schema 3. 双部署模式(同一份二进制)4. License 系统第一天就做
给同行的启示 :– 多协议集成平台, 抽象层是命脉 ——抽象层错了,整个项目推倒重来 – 事件归一化 字段表是项目里最重要的文档 – 双部署模式 不省钱,但 B2B 行业里是必须品 – License 第一天做 ,别等产品上线后补 – 流媒体是 另一个宇宙,单独预算
延伸阅读:– 涂鸦 IoT 开发平台:https://developer.tuya.com – Onvif 协议规范:https://www.onvif.org/profiles/specifications/ – GB/T 28181 平安城市协议(国内同类项目常涉及)– SRS / ZLMediaKit 流媒体服务器选型对比
本文为架构案例研究,技术细节脱胎于真实项目,但具体实现仍在迭代中。文中观点仅供参考,欢迎同行讨论。