物聯網數據采集涉及到大量設備接入、海量的時序數據傳輸,EMQ X MQTT 服務器 與 TDengine 大數據平台的組合技術棧完全能夠勝任場景中的海量時間序列監測數據的傳輸、存儲和計算。
數據入庫后,往往需要其他方式如數據可視化系統將數據按照規則統計、展現出來,實現數據的監控、指標統計等業務需求,以便充分發揮數據的價值,TDengine 搭配開源軟件 Grafana 可以快速搭建物聯網數據可視化平台。
上述整套方案無需代碼開發,涉及的產品均能提供開源軟件、企業服務、雲端 SaaS 服務不同層次的交付模式,能夠根據項目需求實現免費版或企業版私有化落地以及雲端部署。

方案介紹
EMQ X 簡介
EMQ X 是基於高並發的 Erlang/OTP 語言平台開發,支持百萬級連接和分布式集群架構,發布訂閱模式的開源 MQTT 消息服務器。EMQ X 內置了大量開箱即用的功能,其 開源版 EMQ X Broker 及 企業版 EMQ X Enterprise 均支持通過規則引擎將設備消息存儲到 TDengine。
TDengine 是什么
TDengine 是濤思數據專為物聯網、車聯網、工業互聯網、IT 運維等設計和優化的大數據平台。除核心的快 10 倍以上的時序數據庫功能外,還提供緩存、數據訂閱、流式計算等功能,最大程度減少研發和運維的復雜度,且核心代碼,包括集群功能全部開源。
TDengine 提供社區版、企業版和雲服務版,安裝/使用教程詳見 TDengine 使用文檔。
Grafana 簡介
Grafana 是一個跨平台、開源的度量分析和可視化工具,可以查詢處理各類數據源中的數據,進行可視化的展示。它可以快速靈活創建的客戶端圖表,面板插件有許多不同方式的可視化指標和日志,官方庫中具有豐富的儀表盤插件,比如熱圖、折線圖、圖表等多種展示方式;支持 Graphite,TDengine、InfluxDB,OpenTSDB,Prometheus,Elasticsearch,CloudWatch和 KairosDB 等數據源,支持數據項獨立/混合查詢展示;可以創建自定義告警規則並通知到其他消息處理服務或組件中。
業務場景
本文模擬物聯網環境數據采集場景,假設現有一定數據的環境數據采集點,所有采集點數據均通過 MQTT 協議 傳輸至采集平台(MQTT Publish),主題設計如下:
sensor/data
傳感器發送的數據格式為 JSON,數據包括傳感器采集的溫度、濕度、噪聲音量、PM10、PM2.5、二氧化硫、二氧化氮、一氧化碳、傳感器 ID、區域、采集時間等數據。
{
"temperature": 30, "humidity" : 20, "volume": 44.5, "PM10": 23, "pm25": 61, "SO2": 14, "NO2": 4, "CO": 5, "id": "10-c6-1f-1a-1f-47", "area": 1, "ts": 1596157444170 }
現在需要實時存儲以便在后續任意時間查看數據,提出以下的需求:
- 每個設備按照每 5 秒鍾一次的頻率進行數據上報,數據庫需存儲每條數據以供后續回溯分析;
- 通過可視化系統查看 任意區域、任意時間區間內 的指標數據,如平均值、最大值、最小值。
環境准備
本文所用各個組件均有 Docker 鏡像,除 EMQ X 需要修改少數配置為了便於操作使用下載安裝外,TDengine 與 Grafana 均使用 Docker 搭建。
安裝包資源與使用教程參照各自官網:
- EMQ X:EMQ 官網 https://www.emqx.io/cn/
- TDengine:濤思數據官網 https://www.taosdata.com/cn/
- Grafana:Grafana 官網 https://grafana.com/
安裝 EMQ X
如果您是 EMQ X 新手用戶,推薦通過 EMQ X 文檔 快速上手
訪問 EMQ X 下載 頁面下載適合您操作系統的安裝包,本文截稿時 EMQ X 開源版最新版本為 v4.1.1,下載 zip 包的啟動步驟如下 :
## 解壓下載好的安裝包
unzip emqx-macosx-v4.1.1.zip
cd emqx ## 以 console 模式啟動 EMQ X 方便調試 ./bin/emqx console
啟動成功后瀏覽器訪問 http://127.0.0.1:18083 訪問 EMQ X 管理控制台 Dashboard,使用 admin public 默認用戶名密碼完成初次登錄。
EMQ X 企業版 4.1.2 提供了原生 TDengine 寫入插件,性能更好、使用更方便,請移步規則引擎-寫入數據到 TDengine查看
安裝 TDengine
為了方便測試使用通過 Docker 進行安裝(需映射網絡端口),也可以使用安裝包的方式進行安裝:
## 拉取並啟動容器
docker run -d --name tdengine -p 6030-6041:6030-6041 tdengine/tdengine:latest ## 啟動后檢查容器運行狀態 docker ps -a
安裝 Grafana
使用以下命令通過 Docker 安裝並啟動 Grafana:
docker run -d --name=grafana -p 3000:3000 grafana/grafana
啟動成功后瀏覽器訪問 http://127.0.0.1:3000 訪問 Grafana 可視化面板,使用 admin admin 默認用戶名密碼完成初次登錄,登錄后按照提示修改密碼使用新密碼登錄進入主界面:
配置 EMQ X 存儲數據到 TDengine
TDengine 創建數據庫與數據表
進入TDengine Docker 容器:
docker exec -it tdengine bash
創建 test 數據庫:
taos
create database test;
創建 sensor_data 表,關於 TDengine 數據結構以及 SQL 命令參見 TAOS SQL:
use test; CREATE TABLE sensor_data ( ts timestamp, temperature float, humidity float, volume float, PM10 float, pm25 float, SO2 float, NO2 float, CO float, sensor_id NCHAR(255), area TINYINT, coll_time timestamp );
配置 EMQ X 規則引擎
打開 EMQ X Dashboared,進入 規則引擎 -> 規則 頁面,點擊 創建 按鈕進入創建頁面。
規則 SQL
規則 SQL 用於 EMQ X 消息以及事件篩選,以下 SQL 表示從 sensor/data 主題篩選出 payload 數據:
SELECT
payload FROM "sensor/data"
使用 SQL 測試功能 ,輸入測試數據進行篩選結果測試,測試有結果且輸出內容如下,標明 SQL 編寫正確:
{
"payload": "{\"temperature\":30,\"humidity\":20,\"volume\":44.5,\"PM10\":23,\"pm2.5\":61,\"SO2\":14,\"NO2\":4,\"CO\":5,\"id\":\"10-c6-1f-1a-1f-47\",\"area\":1,\"ts\":1596157444170}" }

響應動作
為支持各種不同類型平台的開發,TDengine 提供符合 REST 設計標准的 API。通過 RESTful Connector 提供了最簡單的連接方式,即使用 HTTP 請求攜帶認證信息與要執行的 SQL 操作 TDengine。
使用 EMQ X 開源版中的 發送到 Web 服務 即可通過 RESTful Connector 寫入數據到 TDengine。即將到來的 EMQ X 企業版 4.1.1 版本將提供原生更高性能的寫入 Connector。
發送到 Web 服務需要兩個數據,一個是關聯資源,另一個是消息內容模板。
- 關聯資源:HTTP 服務器配置信息,此處為 TDengine 的 RESTful Connector
- 消息內容模板:此處為攜帶數據的 INSERT SQL,注意我們應當在 SQL 中指定數據庫名,字符類型也要用單引號括起來, 消息內容模板為:
INSERT INTO test.sensor_data VALUES( now, ${payload.temperature}, ${payload.humidity}, ${payload.volume}, ${payload.PM10}, ${payload.pm25}, ${payload.SO2}, ${payload.NO2}, ${payload.CO}, '${payload.id}', ${payload.area}, ${payload.ts} )

創建過程
點擊響應動作下的 添加 按鈕,在彈出框內選擇 發送數據到 Web 服務,點擊 新建資源 新建一個 WebHook 資源。

資源類型選擇 Webhook,請求 URL 填寫 http://127.0.0.1:6041/rest/sql,請求方法選擇 POST, 還需添加 Authorization 請求頭作為認證信息 。
Authorization 的值為 Basic + TDengine 的 {username}:{password} 經過 Base64 編碼之后的字符串, 例如 root:taosdata 編碼后實際填入的值為:Basic cm9vdDp0YW9zZGF0YQ==
在響應動作創建頁面選擇新建的資源,並填入消息模板內容即可。

生成模擬數據
以下腳本模擬了 10000 個設備在過去 24 小時內、每隔 5 秒鍾上報一條模擬數據並發送到 EMQ X 的場景。
- 總數據量: 24 * 3600 / 5 * 100 = 172 萬條
- 消息 TPS: 20
讀者安裝 Node.js ,按需修改配置參數后可以通過以下命令啟動:
npm install mqtt mockjs --save --registry=https://registry.npm.taobao.org
node mock.js
附:模擬生成數據並發送到 EMQ X 代碼,請根據集群性能調整相關參數
// mock.js
const mqtt = require('mqtt') const Mock = require('mockjs') const EMQX_SERVER = 'mqtt://localhost:1883' const CLIENT_NUM = 100 const STEP = 5000 // 模擬采集時間間隔 ms const AWAIT = 5000 // 每次發送完后休眠時間,防止消息速率過快 ms const CLIENT_POOL = [] startMock() function sleep(timer = 100) { return new Promise(resolve => { setTimeout(resolve, timer) }) } async function startMock() { const now = Date.now() for (let i = 0; i < CLIENT_NUM; i++) { const client = await createClient(`mock_client_${i}`) CLIENT_POOL.push(client) } // last 24h every 5s const last = 24 * 3600 * 1000 for (let ts = now - last; ts <= now; ts += STEP) { for (const client of CLIENT_POOL) { const mockData = generateMockData() const data = { ...mockData, id: client.options.clientId, ts, } client.publish('sensor/data', JSON.stringify(data)) } const dateStr = new Date(ts).toLocaleTimeString() console.log(`${dateStr} send success.`) await sleep(AWAIT) } console.log(`Done, use ${(Date.now() - now) / 1000}s`) } /** * Init a virtual mqtt client * @param {string} clientId ClientID */ function createClient(clientId) { return new Promise((resolve, reject) => { const 