TDengine 时序性数据库为什么海量数据下不卡顿呢

语言: CN / TW / HK

本文正在参加「技术专题19期 漫谈数据库技术」活动

前言

TDengine 是一款高性能、分布式、支持 SQL 的时序数据库

  • 学习新知识,无非就是搞懂他是什么,能解决什么痛点,该如何快速入门

功能介绍

  • 他是一个高性能、分布式、支持SQL的时序性数据库,这就是他的功能。
  • 除此以外他还支持缓存、订阅、流计算功能。这么一听是不是感觉TDengine=Mysql+Redis+MQ+Stream了

image-20220507111320561.png

image-20220507111552816.png

使用场景

  • TDengine作为时序性数据库他的场景肯定就是针对那种时序场景。说到时序就是对应我们物联网设备。设备的数据上报是即时性的,在物联网系统中读少写多。其中只有读写,基本不存在删除和更新这两个操作。比如我们的电表数据上报,只会随着时间的递增叠加式推送数据。不可能说前一分钟推送的数据他需要修改一下的。作为点表设备他也不支持这个功能。
  • 所以TDengine的使用场景就是针对物联网,车联网,工业互联等场景。或者说是数据持续性输出的场景,比如我们互联网系统中的日志管理。

image-20220507112302958.png

  • 目前我们公司系统是对医院进行数据采集,从而基于采集设备的数据进行数据汇总报告。
  • 我们有电表测量电流,电压,相位等数据;还有水表测量水压,用水量等数据;还有空调采集设备测量空调出风情况等数据;
  • 而且每一类型的设备中会针对不同地方设置多个设备分别测量。在TDengine中每一种类型对应一张超级表(STable)。同一类型下的设备,每一个设备对应Stable下的一张单独的表。

以下表格摘自于官网

| 设备ID | 时间戳 | | 采集量 | | 标签 | | | --------- | ------------- | ------- | ------- | ----- | ---------------- | ------- | | Device ID | Time Stamp | current | voltage | phase | location | groupId | | d1001 | 1538548685000 | 10.3 | 219 | 0.31 | Beijing.Chaoyang | 2 | | d1002 | 1538548684000 | 10.2 | 220 | 0.23 | Beijing.Chaoyang | 3 | | d1003 | 1538548686500 | 11.5 | 221 | 0.35 | Beijing.Haidian | 3 | | d1004 | 1538548685500 | 13.4 | 223 | 0.29 | Beijing.Haidian | 2 | | d1001 | 1538548695000 | 12.6 | 218 | 0.33 | Beijing.Chaoyang | 2 | | d1004 | 1538548696600 | 11.8 | 221 | 0.28 | Beijing.Haidian | 2 | | d1002 | 1538548696650 | 10.3 | 218 | 0.25 | Beijing.Chaoyang | 3 | | d1001 | 1538548696800 | 12.3 | 221 | 0.31 | Beijing.Chaoyang | 2 |

  • DeviceId对应的就是我们实际的一个采集点的采集设备。Time Stamp是TDengine规定的必有字段。
  • currentvoltagephase分别是设备测量的数据,表示电流,电压,相位等数据
  • locationgroupId是设备的静态属性数据,location可以表示设备出厂厂家地址,groupId可以表示分组批次。总之标签属性可以作为设备的描述功能使用
  • TDengine为什么要这么设计呢?每一个设备对应一张表这样做的好处是每个设备的数据是连贯的且不受干扰的。
  • 另外还有一点一个设备的采集频率是固定,或者说设备采集频率是个常量值,这个在存储的一段时间就能够预测出来的。也方便我们汇总一段时间的数据统计,TDengine也提供函数帮我们统计一段周期INTERVAL(1s, 500a),500毫秒开始统计1S间隔时间内的数据情况。

为什么设备对应表

  • TDengine中有几个关键名词【采集量】【标签】【采集点】
  • 所谓的采集点就是我们的采集设备。在一个物理设备上可以能配备多个采集设备。这个也很好理解比如我们的空调设备就可能有采集电的采集设备,也有采集出风的采集设备。按采集的功能区分的这些采集设备TDengine中可以理解为【采集点】
  • 上面我们已经知道了一个采集点实际上对应一张表,这样就能保证这张表只有一个写入口,所以TDengine就不需要考虑事物的问题了。单入口性能提升很大
  • 1个采集点不一定只采集一处数据,上面的电表采集了电流,电压,相位三个数据,我们称之为【采集量】
  • 针对采集点来说,除了采集量是随着时间的推移不断变换的属性外,还有一些针对设备的描述的属性是不会发生变化的。这些对应TDegine中的【标签】
  • 另外因为一个设备对应一张表,数据都是时效性的,这样在写数据的时候只需要追加即可,从这个角度也能说明TDengine的写入性能会很高。
  • 和mysql按页存储一样,TDengine是按照块进行存储读取的。因为物联网的特性,我们关注的也是一段时间内的数据。所以按块读取也能够提升我们的命中率。比如说用电量,我们不关注某一刻用多少点。我们更加关注的是1天用了多少,1月用了多少。

分的那么彻底,聚合怎么办?

  • 在大数据时代下,分库分表是一种趋势,目前关于分库分表的技术也在不断的迭代完善。TDengine的分表策略正好符合分库分表的需求。在结合TDengine的分布式特性。这就是一种分库分表的实践。关于分库分表我们这里不做赘述
  • 既然你是一种分库分表,那在查询时候需要关联时该怎么办?总不能让我join下去吧。

image-20220507135801919.png

  • 针对医院不同楼层都有单独一套采集设备。e代表电表,这个时候我想看医院一天总用电量,就需要聚合e1-e3电表测量的所有数据。

select * from e1 union all select * from e2 ...

  • 显然,这不是最优的方式,要知道这种代码写在程序里一旦部署了就是静态代码,如果哪天医院电表坏了更换了那么他的DeviceId就不一样了。对于我们程序来说就丢失了新电表的查询记录了。
  • 那么该如何解决呢? TDengine给我引出了超级表的概念。超级表是针对同一类型的设备而言的一种描述性表结构,我们在新添子表时也可以从模板中直接添加

image-20220507140901841.png

  • 根据模板创建表时我们只需要填写标签数据即可

CREATE TABLE ttt USING meters TAGS ("nanjing.liuhe", 2);

安装

  • 好了,前面我们介绍了些TDengine理论性的东西,下面我们就来实际操作一把吧。想要能够操作前我们还的先安装好。官网推荐的方式时Docker 。 我这里也推荐使用Docker方式安装,但是Docker实在没啥可说的,这里我就演示安装包方式安装吧。
  • 点我下载

sudo dpkg -i TDengine-server-2.4.0.18-Linux-x64.deb

  • 安装的时候注意了,如果是集群方式安装那么FQDN需要填写一致

sudo dpkg -r tdengine  # 卸载

image-20220507144756900.png

  • 我们关注的就是cfg目录下是关于TDengine的配置,在安装的时候需要我们配置FQDN,如果设置了又后悔了我们可以在cfg中找到配置。
  • 另外就是data文件夹里存储的是数据表的信息与数据。
  • TDengine是通过systemed方式启动的。关于服务的管理大致我们需要以下命令即可

| 功能 | 命令 | | -- | ------------------------- | | 启动 | systemctl start taosd | | 关停 | systemctl stop taosd | | 重启 | systemctl restart taosd | | 状态 | systemctl status taosd |

  • 服务安装好之后,我们就可以连接数据库了。在server安装中默认会有Client的安装。我们只需要在安装的服务器上输入taos即可。

image-20220507150956570.png

本文正在参加「技术专题19期 漫谈数据库技术」活动