天天看点

使用 TDengine 快速搭建车联网平台

车联网属于物联网的一个分支,通过车载终端采集数据,利用无线网络传输到云服务平台进行持久化存储,最终提供基于实时/历史数据的个性化服务。

目前初创型的车辆网企业,接入的车辆通常低于10万,数据采集频率远远大于1秒。这个级别的数据规模,如果采用HBase系的技术方案,需要至少6台8核32G配置的机器,而采用TDengine作为数据存储引擎,一台2核8G的机器就可以完成。

技术架构

TDengine作为时序处理引擎,可以完全不用Kafka、HDFS/HBase/Spark、Redis等软件,大幅简化大数据平台的设计,降低研发成本和运营成本。因为需要集成的开源组件少,因而系统可以更加健壮,也更容易保证数据的一致性。

  • 基于HBase的解决方案,架构图如下
    使用 TDengine 快速搭建车联网平台

图 1 基于HBase的技术架构图

  • 而基于TDengine的解决方案,架构图如下
使用 TDengine 快速搭建车联网平台

图 2 基于TDengine的技术架构图

数据模型

车载终端采集的数据字段非常多,很多企业按照国标ISO 22901建立数据模型,也有公司按照业务需要使用自定义的数据模型。但通常,采集数据都包含如下字段,本文也采用这种方法构造数据模型。

  • 采集时间(时间戳)
  • 车辆标志(字符串)
  • 经度(双精度浮点)
  • 维度(双精度浮点)
  • 海拔(浮点)
  • 方向(浮点)
  • 速度(浮点)
  • 车牌号(字符串)
  • 车辆型号(字符串)
  • 车辆vid(字符串)

不同于其他时序数据引擎,TDengine为每辆车单独创建一张数据表,数据字段为采集时间、车辆标志、经度、纬度、海拔、方向、速度等与时间序列相关的采集数据;标签字段为车牌号、车辆型号等车辆本身固定的描述信息。这里面有一个小技巧,浮点数据压缩比相对整型数据压缩比很差,经度纬度通常精确到小数点后7位,因此将经度纬度增大1E7倍转为长整型存储,将海拔、方向、速度增大1E2倍转为整型存储。

创建数据库的语句为

1create database db cache 8192 ablocks 2 tblocks 1000 tables 10000;      

创建超级表的SQL语句为

1create 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),那么创建数据表的语句为

1create table v1 using tags(25746, ‘bmw’);      

数据写入

仍然以车辆v1为例,写入一条记录到表v1的SQL语句为

1insert into v1 values(1562150939000,1,2,3,4,5);      

测试数据的生成,可以采用批量数据写入方法,类似

1insert into v1 values(1562150939000,1,1,1,1,1) (1562150969000,2,2,2,2,2) (1562150999000,3,3,3,3,3) (……)(……);      

本文采用C语言编写了一个车辆模拟数据生成程序,该程序首先10万张数据表,然后每张数据表写入1个月的数据(数据间隔1分钟,计44000条数据)

1#include <stdio.h> 
 2#include <stdlib.h>
 3#include <string.h> 
 4#include <unistd.h> 
 5#include "time.h"
 6#include "taos.h"
 7int main(int argc, char *argv[]) {
 8   taos_init();
 9
10   TAOS *taos = taos_connect("127.0.0.1", "root", "taosdata", NULL, 0);
11   if (taos == NULL) {
12     printf("failed to connect to server, reason:%s\n", taos_errstr(taos));
13     exit(1);
14   }
15
16   if (taos_query(taos, "create database db cache 8192 ablocks 2 tblocks 1000 tables 10000") != 0) {
17     printf("failed to create database, reason:%s\n", taos_errstr(taos));
18     exit(1);
19   }
20
21   taos_query(taos, "use db");
22
23   char sql[65000] = "create table vehicles(ts timestamp, longitude bigint, latitude bigint, altitude int, direction int, velocity int) tags(card int, model binary(10))";
24   if (taos_query(taos, sql) != 0) {
25     printf("failed to create stable, reason:%s\n", taos_errstr(taos));
26     exit(1);
27   }
28
29   int begin = time(NULL);
30   for (int table = 0; table < 100000; ++table) {
31     sprintf(sql, "create table v%d using vehicles tags(%d, 't%d')", table, table, table);
32     if (taos_query(taos, sql) != 0) {
33       printf("failed to create table t%d, reason:%s\n", table, taos_errstr(taos));
34       exit(1);
35     }
36
37     for (int loop = 0; loop < 44; loop++) {   
38       int len = sprintf(sql, "insert into v%d values", table);   
39       for (int row = 0; row < 1000; row++) {     
40         len += sprintf(sql + len, "(%ld,%d,%d,%d,%d,%d)", 1561910400000L + 60000L * (row + loop * 1000L), row, row, row, row, row);   
41       }   
42       if (taos_query(taos, sql) != 0) {     
43         printf("failed to insert table t%d, reason:%s\n", table, taos_errstr(taos));   
44       } 
45     }
46   }
47   int end = time(NULL);
48     printf("insert finished, time spend %d seconds", end - begin);
49   }
50}      

将改C文件命名为test.c,在相同目录下创建makefile文件

1ROOT = ./
 2TARGET = exe
 3LFLAGS = -Wl,-rpath,/usr/lib/ -ltaos -lpthread -lm -lrt 
 4CFLAGS = -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/
 5
 6all: $(TARGET)
 7
 8exe:
 9   gcc $(CFLAGS) ./test.c -o $(ROOT)/test $(LFLAGS)
10
11clean:
12   rm $(ROOT)test      

编译之后,将测试程序和数据库在同一台2核8G的台式机上运行,写入时间共计为3946秒,相当于4400000000条/3946秒=111.5万条/秒,折算成点数为111.5*5=557万点/秒。

1insert finished, time spend 3946 seconds      

该程序是单线程运行的,如将其修改成多线程,速度还会有更大提升,但是仅就目前的性能来看,对于车辆网的场景也已经足够。

数据查询

TDengine在数据查询方面做了很多针对时序数据的优化。基于上面生成的测试数据集进行查询,这是一些常见SQL语句的运行结果,性能还是有点吓人的。

TDengine在数据查询方面做了很多针对时序数据的优化。基于上面生成的测试数据集进行查询,这是一些常见SQL语句的运行结果,性能还是有点吓人的。

  • 查询总数
    使用 TDengine 快速搭建车联网平台
    图 3 查询总数
  • 单辆车的明细数据
查询类型 查询时间
1车当前值查询 2.3ms
1车1小时明细查询 2.1ms
1车1日明细查询 6.3ms
1车10日明细查询 15.4ms
1车31日明细查询 31.6ms
使用 TDengine 快速搭建车联网平台

图 4 单辆车的明细数据查询

  • 单辆车的聚合查询
查询类型 查询时间
1车1小时聚合查询 1.9ms
1车1日聚合查询 1.7ms
1车10日聚合查询 2.3ms
1车31日聚合查询 2.2ms
使用 TDengine 快速搭建车联网平台

图 5 单辆车的聚合查询

  • 多辆车的单日聚合查询
查询类型 查询时间
1车单日聚合查询 3.2ms
10车单日聚合查询 5.1ms
100车单日聚合查询 10.4ms
1000车单日聚合查询 51.4ms
10000车单日聚合查询 455.9ms
100000车单日聚合查询 2074.8ms
使用 TDengine 快速搭建车联网平台

图 6 多辆车的单日聚合查询

  • 多辆车单月聚合查询
查询类型 查询时间
1车单月聚合查询 3.1ms
10车单月聚合查询 4.1ms
100车单月聚合查询 7.7ms
1000车单月聚合查询 33.7ms
10000车单月聚合查询 289.5ms
100000车单月聚合查询 1197.ms
使用 TDengine 快速搭建车联网平台

图 7 多辆车单月聚合查询

  • 多辆车单月曲线查询
查询类型 查询时间
1车单月曲线查询 6.9ms
10车单月曲线查询 13.2ms
100车单月曲线查询 75.6ms
1000车单月曲线查询 710.9ms
10000车单月曲线查询 7137.6ms
100000车单月曲线查询 2130.8ms
使用 TDengine 快速搭建车联网平台

图 8 多辆车单月曲线查询

  • 资源消耗
使用 TDengine 快速搭建车联网平台

图 9 Top截图

数据库服务进程只消耗了约2.7GB的内存,CPU占用可以忽略不计。

使用 TDengine 快速搭建车联网平台

图 10 内存占用

结果分析

TDengine提供的时序数据解决方案,单机情况下的平均写入速度在百万条/秒级别,单辆车的所有查询均能做到实时,多辆车的查询速度也非常快,是车联网乃至物联网的必备利器。

关于 TDengine

继续阅读