車聯(lián)網(wǎng)屬于物聯(lián)網(wǎng)的一個分支,通過車載終端采集數(shù)據(jù),利用無線網(wǎng)絡傳輸?shù)皆品掌脚_進行持久化存儲,最終提供基于實時/歷史數(shù)據(jù)的個性化服務。
目前初創(chuàng)型的車輛網(wǎng)企業(yè),接入的車輛通常低于10萬,數(shù)據(jù)采集頻率遠遠大于1秒。這個級別的數(shù)據(jù)規(guī)模,如果采用HBase系的技術(shù)方案,需要至少6臺8核32G配置的機器,而采用TDengine Database作為數(shù)據(jù)存儲引擎,一臺2核8G的機器就可以完成。
技術(shù)架構(gòu)
TDengine Database作為時序處理引擎,可以完全不用Kafka、HDFS/HBase/Spark、Redis等軟件,大幅簡化大數(shù)據(jù)平臺的設計,降低研發(fā)成本和運營成本。因為需要集成的開源組件少,因而系統(tǒng)可以更加健壯,也更容易保證數(shù)據(jù)的一致性。
- 基于HBase的解決方案,架構(gòu)圖如下

- 而基于TDengine的解決方案,架構(gòu)圖如下

數(shù)據(jù)模型
車載終端采集的數(shù)據(jù)字段非常多,很多企業(yè)按照國標ISO 22901建立數(shù)據(jù)模型,也有公司按照業(yè)務需要使用自定義的數(shù)據(jù)模型。但通常,采集數(shù)據(jù)都包含如下字段,本文也采用這種方法構(gòu)造數(shù)據(jù)模型。
- 采集時間(時間戳)
- 車輛標志(字符串)
- 經(jīng)度(雙精度浮點)
- 維度(雙精度浮點)
- 海拔(浮點)
- 方向(浮點)
- 速度(浮點)
- 車牌號(字符串)
- 車輛型號(字符串)
- 車輛vid(字符串)
不同于其他時序數(shù)據(jù)引擎,TDengine為每輛車單獨創(chuàng)建一張數(shù)據(jù)表,數(shù)據(jù)字段為采集時間、車輛標志、經(jīng)度、緯度、海拔、方向、速度等與時間序列相關(guān)的采集數(shù)據(jù);標簽字段為車牌號、車輛型號等車輛本身固定的描述信息。這里面有一個小技巧,浮點數(shù)據(jù)壓縮比相對整型數(shù)據(jù)壓縮比很差,經(jīng)度緯度通常精確到小數(shù)點后7位,因此將經(jīng)度緯度增大1E7倍轉(zhuǎn)為長整型存儲,將海拔、方向、速度增大1E2倍轉(zhuǎn)為整型存儲。
創(chuàng)建數(shù)據(jù)庫的語句為
create database db cache 8192 ablocks 2 tblocks 1000 tables 10000;
創(chuàng)建超級表的SQL語句為
create table vehicle(ts timestamp, longitude bigint, latitude bigint, altitude int, direction int, velocity int) tags(card int, model binary(10));
以車輛vid作為表名(例如vid為1,車牌號為25746,類型為bmw),那么創(chuàng)建數(shù)據(jù)表的語句為
create table v1 using tags(25746, ‘bmw’);
數(shù)據(jù)寫入
仍然以車輛v1為例,寫入一條記錄到表v1的SQL語句為
insert into v1 values(1562150939000,1,2,3,4,5);
測試數(shù)據(jù)的生成,可以采用批量數(shù)據(jù)寫入方法,類似
insert into v1 values(1562150939000,1,1,1,1,1) (1562150969000,2,2,2,2,2) (1562150999000,3,3,3,3,3) (……)(……);
本文采用C語言編寫了一個車輛模擬數(shù)據(jù)生成程序,該程序首先10萬張數(shù)據(jù)表,然后每張數(shù)據(jù)表寫入1個月的數(shù)據(jù)(數(shù)據(jù)間隔1分鐘,計44000條數(shù)據(jù))
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "time.h"
#include "taos.h"
int main(int argc, char *argv[]) {
taos_init();
TAOS *taos = taos_connect("127.0.0.1", "root", "taosdata", NULL, 0);
if (taos == NULL) {
printf("failed to connect to server, reason:%s\n", taos_errstr(taos));
exit(1);
}
if (taos_query(taos, "create database db cache 8192 ablocks 2 tblocks 1000 tables 10000") != 0) {
printf("failed to create database, reason:%s\n", taos_errstr(taos));
exit(1);
}
taos_query(taos, "use db");
char sql[65000] = "create table vehicles(ts timestamp, longitude bigint, latitude bigint, altitude int, direction int, velocity int) tags(card int, model binary(10))";
if (taos_query(taos, sql) != 0) {
printf("failed to create stable, reason:%s\n", taos_errstr(taos));
exit(1);
}
int begin = time(NULL);
for (int table = 0; table < 100000; ++table) {
sprintf(sql, "create table v%d using vehicles tags(%d, 't%d')", table, table, table);
if (taos_query(taos, sql) != 0) {
printf("failed to create table t%d, reason:%s\n", table, taos_errstr(taos));
exit(1);
}
for (int loop = 0; loop < 44; loop++) {
int len = sprintf(sql, "insert into v%d values", table);
for (int row = 0; row < 1000; row++) {
len += sprintf(sql + len, "(%ld,%d,%d,%d,%d,%d)", 1561910400000L + 60000L * (row + loop * 1000L), row, row, row, row, row);
}
if (taos_query(taos, sql) != 0) {
printf("failed to insert table t%d, reason:%s\n", table, taos_errstr(taos));
}
}
}
int end = time(NULL);
printf("insert finished, time spend %d seconds", end - begin);
}
}
將改C文件命名為test.c,在相同目錄下創(chuàng)建makefile文件
ROOT = ./ TARGET = exe LFLAGS = -Wl,-rpath,/usr/lib/ -ltaos -lpthread -lm -lrt CFLAGS = -O3 -g -Wall -Wno-deprecated -fPIC -Wno-unused-result -Wconversion -Wno-char-subscripts -D_REENTRANT -Wno-format -D_REENTRANT -DLINUX -msse4.2 -Wno-unused-function -D_M_X64 -std=gnu99 -I/usr/local/include/taos/ all: $(TARGET) exe: gcc $(CFLAGS) ./test.c -o $(ROOT)/test $(LFLAGS) clean: rm $(ROOT)test
編譯之后,將測試程序和數(shù)據(jù)庫在同一臺2核8G的臺式機上運行,寫入時間共計為3946秒,相當于4400000000條/3946秒=111.5萬條/秒,折算成點數(shù)為111.5*5=557萬點/秒。
insert finished, time spend 3946 seconds
該程序是單線程運行的,如將其修改成多線程,速度還會有更大提升,但是僅就目前的性能來看,對于車輛網(wǎng)的場景也已經(jīng)足夠。
數(shù)據(jù)查詢
TDengine在數(shù)據(jù)查詢方面做了很多針對時序數(shù)據(jù)的優(yōu)化?;谏厦嫔傻臏y試數(shù)據(jù)集進行查詢,這是一些常見SQL語句的運行結(jié)果,性能還是有點嚇人的。
- 查詢總數(shù)

- 單輛車的明細數(shù)據(jù)
| 查詢類型 | 查詢時間 |
|---|---|
| 1車當前值查詢 | 2.3ms |
| 1車1小時明細查詢 | 2.1ms |
| 1車1日明細查詢 | 6.3ms |
| 1車10日明細查詢 | 15.4ms |
| 1車31日明細查詢 | 31.6ms |

- 單輛車的聚合查詢
| 查詢類型 | 查詢時間 |
|---|---|
| 1車1小時聚合查詢 | 1.9ms |
| 1車1日聚合查詢 | 1.7ms |
| 1車10日聚合查詢 | 2.3ms |
| 1車31日聚合查詢 | 2.2ms |

- 多輛車的單日聚合查詢
| 查詢類型 | 查詢時間 |
|---|---|
| 1車單日聚合查詢 | 3.2ms |
| 10車單日聚合查詢 | 5.1ms |
| 100車單日聚合查詢 | 10.4ms |
| 1000車單日聚合查詢 | 51.4ms |
| 10000車單日聚合查詢 | 455.9ms |
| 100000車單日聚合查詢 | 2074.8ms |

- 多輛車單月聚合查詢
| 查詢類型 | 查詢時間 |
|---|---|
| 1車單月聚合查詢 | 3.1ms |
| 10車單月聚合查詢 | 4.1ms |
| 100車單月聚合查詢 | 7.7ms |
| 1000車單月聚合查詢 | 33.7ms |
| 10000車單月聚合查詢 | 289.5ms |
| 100000車單月聚合查詢 | 1197.ms |

- 多輛車單月曲線查詢
| 查詢類型 | 查詢時間 |
|---|---|
| 1車單月曲線查詢 | 6.9ms |
| 10車單月曲線查詢 | 13.2ms |
| 100車單月曲線查詢 | 75.6ms |
| 1000車單月曲線查詢 | 710.9ms |
| 10000車單月曲線查詢 | 7137.6ms |
| 100000車單月曲線查詢 | 32130.8ms |

- 資源消耗

數(shù)據(jù)庫服務進程只消耗了約2.7GB的內(nèi)存,CPU占用可以忽略不計。

結(jié)果分析
TDengine Database提供的時序數(shù)據(jù)解決方案,單機情況下的平均寫入速度在百萬條/秒級別,單輛車的所有查詢均能做到實時,多輛車的查詢速度也非??欤擒嚶?lián)網(wǎng)乃至物聯(lián)網(wǎng)的必備利器。



互聯(lián)網(wǎng).png)



-1.png)











伙伴.png)
伙伴.png)



