车联网开发入门:Docker 搭建 EMQX + TDengine,跑通第一条车联网消息

大概花了两个小时,从零把车联网最核心的两个组件------MQTT Broker 和时序数据库------在本地跑起来了。


一、为什么要学 MQTT?

之前做后端,接口通信基本都是 HTTP。但车联网场景下,HTTP 有几个很明显的短板。

HTTP 的问题在哪?

平时写 Spring Boot 接口,客户端发请求 → 服务端响应,没问题。但如果是一辆车每秒上报一次 GPS,用 HTTP 的话每次都要 TCP 三次握手,一万辆车就是每秒一万次握手,连接开销大到不划算。

还有一个更直观的问题:服务端想主动给车发指令怎么办?比如远程开空调。HTTP 是「请求-响应」模型,服务端没能力主动推送,只能靠车机轮询------隔几秒问一次「有没有新指令」,大部分时候都是空转,耗电耗流量。

地库、隧道这种弱网环境下,HTTP header 大几百字节,丢包重传成本也高。

MQTT 怎么解决的?

MQTT 是一种发布/订阅模式的轻量级消息协议,设计之初就是给物联网用的。

复制代码
车辆(发布者)──发布 Topic: vehicle/001/data ──→ EMQX Broker ←──订阅 Topic: vehicle/+/data ── Java 后端

核心区别:

维度 HTTP MQTT
通信模型 请求-响应 发布-订阅
连接 短连接,用完即断 长连接,一直保持
消息方向 只能客户端主动 双向收发
消息头 几百字节 最小 2 字节
弱网 频繁重连 自动重连 + 离线缓存

QoS 三级------这个很重要

QoS 是 MQTT 最核心的设计:

  • QoS 0:发一次,丢了不管。适合 GPS 上报,丢了就丢了,下一秒还有新的。
  • QoS 1:至少送到一次,可能重复。适合状态上报,收到就行,多一次没关系。
  • QoS 2:精确送达一次,绝不重复。适合远程控车指令------重复执行会出事故。

二、EMQX 和 MQTT 是什么关系?

刚开始很容易搞混,其实很简单:

MQTT 是协议标准(就像 SQL),EMQX 是具体实现(就像 MySQL)。学了 MQTT 概念,得装个 Broker 才能真正用起来。

市面上几个主流的 MQTT Broker:

  • Mosquitto:很轻量,适合嵌入式和测试,功能简单
  • EMQX:分布式、高性能,支持 MQTT 5.0、WebSocket、规则引擎,车联网项目用得多
  • HiveMQ:商业付费为主
  • NanoMQ:也是 EMQ 团队的,跑在边缘端,比如车机本身

选 EMQX 主要是因为它自带 Dashboard,对新手友好。不装任何客户端,浏览器打开就能看到连接数、消息量、Topic 列表。

查资料的时候发现 B 站上 EMQX 的教程不多,一开始也担心是不是过时了。后来看了下 GitHub 有 14k+ Star,2025 年 11 月刚发 6.0 大版本,其实是因为这种基础设施类的技术,主流学习方式就是看官方文档和动手实践,不像前端框架那样视频教程满天飞。


三、为什么要学 TDengine?

车联网数据有个特点:每条记录都带时间戳,写入多、更新少、几乎不删,查询也是按时间范围。这种数据类型叫「时序数据」。

MySQL 存时序数据很吃力:

  • 行存 + B+Tree 索引,写入几千条/秒到头了
  • 百万辆车每秒一条,MySQL 根本写不动
  • 磁盘占用大,基本不压缩
  • 按时间范围查大数据量时很慢

TDengine 专门为这种场景设计:

  • 列存,按时间段压缩,写入百万条/秒
  • 压缩比 10:1,省磁盘
  • 内置降采样、插值、窗口函数,聚合查询很快
  • 支持 SQL 和 JDBC,Java 开发直接用

四、动手搭建环境

官方文档是最好的教程,我按照 Quick Start 一步步来的。

前置:Docker

先确认 Docker 能用:

powershell 复制代码
docker --version
docker ps

国内网络要配镜像加速,编辑 C:\Users\你的用户名\.docker\daemon.json

json 复制代码
{
  "registry-mirrors": [
    "https://docker.1panel.live",
    "https://dockerproxy.net",
    "https://hub-mirror.c.163.com"
  ]
}

改完重启 Docker Desktop。

Step 1:装 EMQX

参考:https://www.emqx.io/docs/zh/latest/getting-started/

powershell 复制代码
docker run -d --name emqx -p 1883:1883 -p 18083:18083 emqx/emqx:latest
  • 1883:MQTT 协议端口,设备连这个
  • 18083:Dashboard 管理界面

浏览器打开 http://localhost:18083,账号 admin,密码 public,登录后就能看到管理后台。

Step 2:装 TDengine

参考:https://docs.tdengine.com/get-started/

powershell 复制代码
docker run -d --name tdengine -p 6030:6030 -p 6041:6041 -p 6060:6060 tdengine/tdengine:latest
  • 6030:客户端连接端口(Java JDBC 用这个)
  • 6041:REST API 端口(taosAdapter)
  • 6060:Web 控制台(taosExplorer,3.x 版本新增)

浏览器打开 http://localhost:6060,账号 root,密码 taosdata。

到这一步,两个核心组件就都在 Docker 里跑起来了。

Step 3:用 MQTTX 发第一条消息

MQTTX 是官方出的 MQTT 桌面调试工具,下载地址:https://mqttx.app/

安装后新建连接:

  • Host: localhost
  • Port: 1883

连接成功后会显示绿色的 Connected。

然后发一条消息:

  • Topic: vehicle/001/data
  • QoS: 1
  • Payload:
json 复制代码
{
  "vin": "VIN001",
  "speed": 60,
  "battery": 85,
  "lat": 30.5928,
  "lng": 114.3055
}

点击发送。去 EMQX Dashboard 的 Monitoring 页面能看到消息计数在涨------说明消息成功经过 Broker 了。这时候感觉挺奇妙的,虽然是模拟的,但这就是真实车联网场景的最小原型。

Step 4:TDengine 建表并查询

打开 TDengine 控制台 http://localhost:6060,在 Explorer 的 SQL 编辑器里逐条执行。

4.1 创建数据库
sql 复制代码
CREATE DATABASE vehicle KEEP 365d;
  • vehicle:数据库名,后面所有表都建在这个库下面
  • KEEP 365d:数据保留 365 天,超过自动删除。车联网数据量大,必须设过期策略,不然磁盘很快就满
4.2 创建超级表
sql 复制代码
CREATE STABLE vehicle.t_vehicle_data (
  ts TIMESTAMP,
  speed INT,
  battery INT,
  lat DOUBLE,
  lng DOUBLE
) TAGS (vin NCHAR(20));

这条值得拆开说。

超级表(STable)是 TDengine 和 MySQL 最大的不同。所有车的数据结构都一样------时间、速度、电量、经纬度,如果 100 万辆车建 100 万张表,管理成本太高。超级表就是「模板表」:

  • 括号内(tsspeedbatterylatlng):数据列,每辆车都存这些字段
  • TAGS (vin NCHAR(20)):标签列,用来区分不同车辆。这里用 VIN 码(车架号)做标签,每辆车唯一

类比一下的话,超级表像 Java 里的抽象类,子表是具体实例。建好模板之后,每辆车只需要一行 CREATE TABLE ... USING 就能有自己的子表。

4.3 创建子表
sql 复制代码
CREATE TABLE vehicle.v_vin001 USING vehicle.t_vehicle_data TAGS ('VIN001');
  • v_vin001:子表名,命名规则是 v_ + VIN 码,一眼就知道是哪辆车
  • USING vehicle.t_vehicle_data:继承超级表的列定义
  • TAGS ('VIN001'):给这辆车的标签赋值

建完之后,这辆车就有了 tsspeedbatterylatlng 五个数据列,标签标记为 VIN001。以后要查这辆车的所有数据,直接 SELECT * FROM vehicle.v_vin001 就行。

4.4 插入数据
sql 复制代码
INSERT INTO vehicle.v_vin001 VALUES (NOW, 60, 85, 30.5928, 114.3055);
  • NOW:当前时间戳,TDengine 自动填充
  • 后面依次是速度 60、电量 85%、纬度 30.5928、经度 114.3055(武汉坐标)
  • 不用写 vin 字段,因为标签已经在建表时固定了
4.5 查询验证
sql 复制代码
SELECT * FROM vehicle.v_vin001;

能看到一条记录就说明整条链路通了。

💡 超级表的真正威力后面才会体现:当你有 100 个子表(100 辆车),可以对超级表直接 SELECT AVG(speed) FROM vehicle.t_vehicle_data WHERE ts > ...,一次查询覆盖所有车,不用 UNION ALL

小结一下环境:

复制代码
Docker
 ├── EMQX     ← MQTT 消息中枢   → http://localhost:18083
 └── TDengine ← 时序数据仓库    → http://localhost:6060

五、踩坑记录

1. Docker 拉镜像超时

配镜像加速后重启 Docker Desktop 解决。

2. 装了之后 Docker 一堆容器自启动

之前装的 RocketMQ、Redis、MySQL 每次开机都起来,占用资源。用 docker stop xxx 停掉,docker rm xxx 删掉就干净了。Docker Desktop 设置里还可以关掉开机自启。

3. EMQX 和 MQTT 混淆

一开始以为 EMQX 就是 MQTT,后来才理清:MQTT 是协议,EMQX 是实现。就像 HTTP 和 Nginx 的关系。


六、学完的感受

之前对 MQTT 的理解只停留在「物联网用的协议」,时序数据库也只是听说过。亲手搭一遍之后感觉完全不一样了:

  • Topic 的设计、QoS 三级、发布订阅模型,写代码的时候知道选什么了
  • TDengine 的超级表结构,建过表之后比看文档直观多了
  • 从 MQTTX → EMQX → 浏览器 Dashboard,亲眼看到消息流过的路径

下一篇准备用 Java 代码取代 MQTTX,Spring Boot 集成 Eclipse Paho,把接收到的消息直接写进 TDengine。


车联网学习笔记,持续更新。