1.起因

目前公司主要是做物联网方面的业务,之前为了快速开发和方便维护,设备(传感器)的数据也使用了MySQL进行存储。起初项目数据量小,系统并无问题,但随着传感器的数据越来越多,目前单表已经有了7700w,查询、关联等操作变得很慢,也在不断的优化索引、SQL语句甚至读写分离与迁移数据,但毕竟我不是专业的DBA,维护这些东西很吃力。偶然的机会下,首先是接触到了IotDB这种时序性数据库,发现这种时序性数据库非常锲合我们的业务背景(其实应该是锲合所有的物联网项目),然后我开始了解市场上现在都有哪几种时序性数据库,包括有IotDB、InfluxDB等,也了解了列式存储的数据库,如:ClickHouse。在之前研究EMQX的时候,论坛有个老哥加了我的微信,和我探讨了一些问题,他说他们是要利用EMQX的WebHook调用TDengine的Restful接口进行设备消息存储,在和他的探讨下,我也了解了一下关于TDengine这个数据库,了解了以后我深深叹了一口气,不得不佩服TDengine的强大。之前因为一些原因,我离开了公司一段时间,目前又回来了,哈哈,也算二进宫了,之后的话会考虑把传感器数据放到TDengine数据库中,道阻且长。

官网地址:https://www.taosdata.com/cn/
1.png

2.安装TDengine数据库

我准备了一台云服务器,配置算是入门配置吧,正好测试一下TDengine数据库在配置低的情况下的运行效果
2.png
我们从官网上下载安装包
3.png
会要求填一个邮箱号,然后会把下载链接发到邮箱里,我这里直接给大家贴一个出来吧

https://www.taosdata.com/assets-download/TDengine-server-2.0.20.12-Linux-x64.rpm

下载完成后上传到服务器上,进行安装

  1. rpm -ivh TDengine-server-2.0.20.12-Linux-x64.rpm

4.png
中途遇到需要输入的地方直接回车即可,这样我们就安装完成了,然后我们查看一下TDengine目前的状态

  1. systemctl status taosd

5.png
然后我们启动一下

  1. systemctl start taosd

6.png

3.简单测试

我们安装的这个版本内置客户端,直接在命令行使用taos即可进入交互页面,然后我们做几个简单操作

  1. taos> show databases;
  2. name | created_time | ntables | vgroups | replica | quorum | days | keep0,keep1,keep(D) | cache(MB) | blocks | minrows | maxrows | wallevel | fsync | comp | cachelast | precision | update | status |
  3. ====================================================================================================================================================================================================================================================================================
  4. log | 2021-08-13 14:51:31.150 | 4 | 1 | 1 | 1 | 10 | 30,30,30 | 1 | 3 | 100 | 4096 | 1 | 3000 | 2 | 0 | us | 0 | ready |
  5. Query OK, 1 row(s) in set (0.001006s)
  6. taos> create database water;
  7. Query OK, 0 of 0 row(s) in database (0.003380s)
  8. taos> use water;
  9. Database changed.
  10. taos> create table 0001 (ts timestamp,pressure double);
  11. DB error: invalid SQL: invalid table name (0.000306s)
  12. taos> create table 0001 (ts timestamp,pressure double);
  13. DB error: invalid SQL: invalid table name (0.000595s)
  14. taos> create table water.1 (ts timestamp,pressure double);
  15. DB error: syntax error near ".1 (ts timestamp,pressure double);" (0.000124s)
  16. taos> create table water1 (ts timestamp,pressure double);
  17. Query OK, 0 of 0 row(s) in database (0.016558s)
  18. taos> show tables;
  19. table_name | created_time | columns | stable_name | uid | tid | vgId |
  20. ==========================================================================================================================================================
  21. water1 | 2021-08-13 14:57:46.659 | 2 | | 844424946914236 | 1 | 3 |
  22. Query OK, 1 row(s) in set (0.001993s)
  23. taos> insert into t values ('2020-01-01 00:00:00', 12.3);
  24. DB error: Table does not exist (0.000351s)
  25. taos> insert into water1 values ('2020-01-01 00:00:00', 12.3);
  26. Query OK, 1 of 1 row(s) in database (0.000634s)
  27. taos> insert into water1 values (now, 17.3);
  28. Query OK, 1 of 1 row(s) in database (0.000367s)
  29. taos> select * from water1;
  30. ts | pressure |
  31. ======================================================
  32. 2020-01-01 00:00:00.000 | 12.300000000 |
  33. 2021-08-13 14:58:59.853 | 17.300000000 |
  34. Query OK, 2 row(s) in set (0.001054s)
  35. taos> select * from water.water1;
  36. ts | pressure |
  37. ======================================================
  38. 2020-01-01 00:00:00.000 | 12.300000000 |
  39. 2021-08-13 14:58:59.853 | 17.300000000 |
  40. Query OK, 2 row(s) in set (0.000838s)
  41. taos> select * from water.water1 order by ts desc;
  42. ts | pressure |
  43. ======================================================
  44. 2021-08-13 14:58:59.853 | 17.300000000 |
  45. 2020-01-01 00:00:00.000 | 12.300000000 |
  46. Query OK, 2 row(s) in set (0.001758s)
  47. taos> drop table water1;
  48. Query OK, 0 of 0 row(s) in database (0.006572s)
  49. taos> drop database water;
  50. Query OK, 0 of 0 row(s) in database (0.007274s)
  51. taos> exit

对表名的起名是有规范的,我一开始不知道
7.png
而且我们这个直接使用taos进入命令行这种操作是不是有点……不安全,等我再仔细研究一下试试
其实用taos直接进入是使用用户名root 密码taosdata进入的,我们可以使用命令行修改密码

  1. alter user root pass 'zym123456,.' ;

然后我们使用taos进入数据库
image.png
可以看到已经登不上去了,我们用新密码登录试试
image.png
这样就可以解决大家担心的直接使用taos就可进入数据库的操作

官方也给出了一些参数
8.png

4.TDengine的真正强大之处

官方提供了一个demo,我们跑起来玩一下

启动TDengine的服务,在Linux终端执行taosdemo

该命令将在数据库 test 下面自动创建一张超级表 meters,该超级表下有 1 万张表,表名为 “d0” 到 “d9999”,每张表有 1 万条记录,每条记录有 (ts, col1, col2, col3) 四个字段,时间戳从 “2017-07-14 10:40:00 000” 到 “2017-07-14 10:40:09 999”,每张表带有标签 location 和 groupId,groupId 被设置为 1 到 10, location 被设置为 “beijing” 或者 “shanghai”。

  1. [root@VM-4-8-centos ~]# taosdemo;
  2. taosdemo is simulating data generated by power equipments monitoring...
  3. host: 127.0.0.1:6030
  4. user: root
  5. password: taosdata
  6. configDir:
  7. resultFile: ./output.txt
  8. thread num of insert data: 10
  9. thread num of create table: 10
  10. top insert interval: 0
  11. number of records per req: 30000
  12. max sql length: 1048576
  13. database count: 1
  14. database[0]:
  15. database[0] name: test
  16. drop: yes
  17. replica: 1
  18. precision: ms
  19. super table count: 1
  20. super table[0]:
  21. stbName: meters
  22. autoCreateTable: no
  23. childTblExists: no
  24. childTblCount: 10000
  25. childTblPrefix: d
  26. dataSource: rand
  27. iface: taosc
  28. insertRows: 10000
  29. interlaceRows: 0
  30. disorderRange: 1000
  31. disorderRatio: 0
  32. maxSqlLen: 1048576
  33. timeStampStep: 1
  34. startTimestamp: 2017-07-14 10:40:00.000
  35. sampleFormat:
  36. sampleFile:
  37. tagsFile:
  38. columnCount: 3
  39. column[0]:FLOAT column[1]:INT column[2]:FLOAT
  40. tagCount: 2
  41. tag[0]:INT tag[1]:BINARY(16)
  42. Press enter key to continue or Ctrl-C to stop
  43. create database test success!
  44. 已杀死

已杀死……这配置跑不起来,换虚拟机……

我在虚拟机用docker跑起来的,直接执行下面命令即可

  1. docker run -d tdengine/tdengine

9.png
然后我们进入容器内执行taosdemo即可

  1. docker exec -it tdengine /bin/bash
  1. root@a92fbfa78c9f:~/TDengine-server-2.1.0.0# taosdemo
  2. host: 127.0.0.1:6030
  3. user: root
  4. password: taosdata
  5. configDir:
  6. resultFile: ./output.txt
  7. thread num of insert data: 10
  8. thread num of create table: 10
  9. top insert interval: 0
  10. number of records per req: 30000
  11. max sql length: 1048576
  12. database count: 1
  13. database[0]:
  14. database[0] name: test
  15. drop: yes
  16. replica: 1
  17. precision: ms
  18. super table count: 1
  19. super table[0]:
  20. stbName: meters
  21. autoCreateTable: no
  22. childTblExists: no
  23. childTblCount: 10000
  24. childTblPrefix: t
  25. dataSource: rand
  26. insertMode: taosc
  27. childTblOffset: 0
  28. insertRows: 10000
  29. interlaceRows: 0
  30. disorderRange: 1000
  31. disorderRatio: 0
  32. maxSqlLen: 1048576
  33. timeStampStep: 1
  34. startTimestamp: 2017-07-14 10:40:00.000
  35. sampleFormat:
  36. sampleFile:
  37. tagsFile:
  38. columnCount: 4
  39. column[0]:INT column[1]:INT column[2]:INT column[3]:INT
  40. tagCount: 2
  41. tag[0]:INT tag[1]:BINARY(16)
  42. Press enter key to continue
  43. create database test success!
  44. Spent 2.0440 seconds to create 10000 tables with 10 thread(s)
  45. thread[0] has currently inserted rows: 2730000, affected rows: 2730000
  46. thread[6] has currently inserted rows: 2620000, affected rows: 2620000
  47. thread[8] has currently inserted rows: 2750000, affected rows: 2750000
  48. thread[5] has currently inserted rows: 2750000, affected rows: 2750000
  49. thread[2] has currently inserted rows: 2770000, affected rows: 2770000
  50. thread[9] has currently inserted rows: 2690000, affected rows: 2690000
  51. thread[7] has currently inserted rows: 2680000, affected rows: 2680000
  52. thread[4] has currently inserted rows: 2760000, affected rows: 2760000
  53. thread[3] has currently inserted rows: 2750000, affected rows: 2750000
  54. thread[1] has currently inserted rows: 2690000, affected rows: 2690000
  55. thread[0] has currently inserted rows: 5490000, affected rows: 5490000
  56. thread[8] has currently inserted rows: 5610000, affected rows: 5610000
  57. thread[6] has currently inserted rows: 5420000, affected rows: 5420000
  58. thread[5] has currently inserted rows: 5410000, affected rows: 5410000
  59. thread[4] has currently inserted rows: 5520000, affected rows: 5520000
  60. thread[9] has currently inserted rows: 5520000, affected rows: 5520000
  61. thread[7] has currently inserted rows: 5440000, affected rows: 5440000
  62. thread[2] has currently inserted rows: 5490000, affected rows: 5490000
  63. thread[3] has currently inserted rows: 5630000, affected rows: 5630000
  64. thread[1] has currently inserted rows: 5430000, affected rows: 5430000
  65. thread[0] has currently inserted rows: 8140000, affected rows: 8140000
  66. thread[2] has currently inserted rows: 8240000, affected rows: 8240000
  67. thread[6] has currently inserted rows: 8200000, affected rows: 8200000
  68. thread[5] has currently inserted rows: 8050000, affected rows: 8050000
  69. thread[8] has currently inserted rows: 8300000, affected rows: 8300000
  70. thread[7] has currently inserted rows: 8170000, affected rows: 8170000
  71. thread[9] has currently inserted rows: 8190000, affected rows: 8190000
  72. thread[4] has currently inserted rows: 8240000, affected rows: 8240000
  73. thread[3] has currently inserted rows: 8430000, affected rows: 8430000
  74. thread[1] has currently inserted rows: 8230000, affected rows: 8230000
  75. ====thread[3] completed total inserted rows: 10000000, total affected rows: 10000000====
  76. ====thread[8] completed total inserted rows: 10000000, total affected rows: 10000000====
  77. ====thread[6] completed total inserted rows: 10000000, total affected rows: 10000000====
  78. ====thread[2] completed total inserted rows: 10000000, total affected rows: 10000000====
  79. ====thread[1] completed total inserted rows: 10000000, total affected rows: 10000000====
  80. ====thread[4] completed total inserted rows: 10000000, total affected rows: 10000000====
  81. ====thread[7] completed total inserted rows: 10000000, total affected rows: 10000000====
  82. ====thread[9] completed total inserted rows: 10000000, total affected rows: 10000000====
  83. ====thread[0] completed total inserted rows: 10000000, total affected rows: 10000000====
  84. ====thread[5] completed total inserted rows: 10000000, total affected rows: 10000000====
  85. Spent 109.88 seconds to insert rows: 100000000, affected rows: 100000000 with 10 thread(s) into test.meters. 910125 records/second
  86. insert delay, avg: 92.67ms, max: 328ms, min: 9ms

耗时110秒,插入了一亿条数据,我惊呆了。。。

然后我们去各种维度的查询一下看看时间

首先看一下表里面都有哪些字段,我们查询超级表字段即可
10.png
1.查询1亿条数据的col0的最大值,col1的平均值,col2的最大值,col3的最小值
11.png
2.查询从第十万条开始,往后查询一千条数据
12.png
13.png
可以看到是非常快的

3.聚合查询,根据t1字段进行分组查询col1的平均值
14.png
体验完这次demo后,大家都能看到TDengine的强大之处,无论是怎么样查询,都可以保证数据在极快的时间内返回结果,在大数据量面前甩开MySQL几条街了~