这是一个物联网项目

整体链路如下:

传感器 → TCP Server(Netty) → TCP → MQTT Bridge → EMQX
后端消费者基于 EMQX 再落库(InfluxDB / MySQL / Redis / AI 模型)

为了验证系统抗压能力,我使用 Python 编写 TCP 客户端,模拟多传感器长连接 + 周期性上报,结果在压测过程中,连续踩中了多个典型但非常隐蔽的坑。

下面是对踩坑过程的完整复盘

问题现象

1. 设备数量异常增长

压测一段时间后,数据库中出现了大量“新设备”,明明只模拟了 10 个设备,实际却创建了 200+ 条 device 记录,而且 device_sn 出现诡异值,如:

WT6B0000000\u0001
WT6B0000000\u0002
WT6B0000000\u0003

2. MQTT 发布失败

EMQX 日志持续报错:

Invalid UTF-8 char: [1]

3. 解析数据明显异常

同一设备,第一次数据完全正常,后续数据角度、电压、阈值全部失真,解析类型从 0x0100 变成了 0x3B01

但 TCP Server 没有报异常

开始以为是数据库业务逻辑问题

最开始怀疑的是:

  • MyBatis 的 select + insert 并发问题
  • 设备注册逻辑设计不当

确实,这段代码在并发下是有设计缺陷的

IotDevice device = selectBySn(sn);
if (device == null) {
    insert(device);
}
update(device);

但将这部分代码先注释掉,再次运行后发现,问题依旧存在。

数据库问题只是放大器,真正的根本原因在 TCP 层。

根本原因:TCP 粘包 + 帧错位

1. TCP 的粘包问题

TCP 没有消息边界,只保证字节流有序。

这意味着:一次 send() ≠ 一次 read();多个设备并发时,字节流极易错位

2. 错位带来的连锁反应

一旦 42 字节协议帧发生错位:

  • 设备 ID 的最后一个字节被解析成 0x01 / 0x02 / 0x03
  • Java 用 byte → char 转 String
  • 生成了随机字符甚至直接生成了非法 UTF-8 字符
  • MQTT publish 失败 or 数据库误判为新设备

所以数据库里看到的并不是多设备,而是:同一设备的 ID 被 TCP 粘包打碎了。

为什么已经用 FixedLengthFrameDecoder 了还不行?

我一开始的 Netty pipeline 是这样的:

pipeline.addLast(new FixedLengthFrameDecoder(42));
pipeline.addLast(new RailwayProtocolDecoder());
pipeline.addLast(new RailwayTcpHandler());

但问题仍然存在。

问题在模拟脚本

Python 模拟脚本中,设备 ID 是二进制自增,而不是 ASCII

hex_list[11] = f"{device_no:02X}"   #

这会直接产生:

0x01 0x02 0x03 ...

而协议定义中的设备 ID 实际是:

"WT6B00000001"  → ASCII '0' '1'

最终修复方案

1.协议层彻底对齐

  • 固定 42 字节
  • 所有设备 ID 严格 ASCII
  • 禁止任何非可见字符进入 device_sn
frame[11] = f"{0x30 + device_no:02X}"  # '1' → 0x31

2.Netty 做帧切割

pipeline.addLast(new FixedLengthFrameDecoder(42));

3.MQTT 发布必须明确 UTF-8

byte[] payload = mapper.writeValueAsBytes(data);
MqttMessage msg = new MqttMessage(payload);

不要隐式 getBytes()

4.数据库层兜底

  • device_sn 加唯一索引
  • 使用 INSERT ... ON DUPLICATE KEY UPDATE
  • 不再用 select + insert

在超高并发设备注册场景下,即使是这条SQL也可能成为瓶颈。后面我将引入缓存(Redis)做一层SN的快速判重

最终效果

在修复后进行压力测试:

  • 200+ TCP 长连接稳定
  • 固定设备数量,无新增“幽灵设备”
  • MQTT 发布成功率 100%
  • 数据解析长期稳定
  • EMQX 消费链路正常
分类: Java-BackendProjects 标签: 实战

评论

暂无评论数据

暂无评论数据

目录