如何在TDengine上进行数据建模、集群搭建、告警模块搭建?如何将数据更平滑地迁移到TDengine?在这些操作中,可能会遇到什么问题?又该如何解决?从湖南必和必拓的实践经验出发,本文将从代码层面一一解答。
业务场景及痛点
在一些业务场景中,我们需要将长沙市在建工地的扬尘数据(温度、湿度、pm2.5、pm10、pm100、噪声、风向、风速)存储在数据库中,以便为业务提供查询、分析和统计的操作。
但近来出现了一个难题,我们共有监测点107个,每分钟上送1条数据,每年就预计有“107*60*24*365 = 56,239,200”条数据,也就是5600多万条。目前已存储两年的数据,数据量总计约1亿多条。这些数据一直都被存储在MySQL数据库中,庞大的数据量使得查询速度越发缓慢,甚至部分页面出现超时问题。
解决方案1:MySQL数据库分库分表
如果我们将数据库分散到不同的表上,单表的索引大小就得到了控制,对索引以及表结构的变更会变得更加方便和高效。当数据库实例的吞吐量达到性能的瓶颈时,我们需要扩展数据库实例,让每个数据库实例承担其中一部分数据库的请求,分解总体的大请求量的压力。
弊端:
分库分表需要提前对数据做好规划。如果按照时间对表进行水平划分,随着监控点增加,后面的表数据量可能越来越大,容易出现数据热点问题;如果按照监测点hash取模对表进行水平划分,当监测点增加,进行扩展就会比较困难。例如:之前是mod4,后面是mod6,则需要对之前的历史数据重新进行处理。
在对数据进行统计分析时,可能需要进行多表的聚合查询,查询速度会受到影响。
解决方案2:使用华为云物联网平台
华为云物联网基于物联网资产模型,整合物联网数据集成、清洗、存储、分析、可视化,为物联网数据开发者提供一站式服务,能够有效降低开发门槛,缩短开发周期,快速实现物联网数据价值变现。
弊端:前期需设备厂商针对平台接口进行适配,接入以后零代码的方式确实在配置上会比较方便,但是平台的费用以及实时流式计算按次收费的方式,整体费用过高。
解决方案3:使用物联网数据库
InfluxDB:高性能的时序数据库,可以高效的存储和查询时序数据。可惜的是,目前社区版集群功能不开源。
TDengine:TDengine是一个简单快捷、高性能的时序数据库,提供高性能的同时也极大降低了安装、部署和维护的成本。应用之后,TDengine能解决之前令我们较为头疼的一些问题,包括前文中描述的问题,它有以下5点主要优势:
1)安装简单。下载rpm包,一个命令安装完毕即可运行。
2)数据库开源,支持集群。
3)充分考虑时序数据的特点,以超级表为模型,将每个监测点的数据单独存储在一张表中,提高了插入和查询速度。
4)有丰富的函数,支持窗口查询和连续查询。
5)自带TDengineAlert模块,和AlertManager联合使用,可以推送告警信息
关于TDengine安装
[root@hnbhbt ~]# tar -zxvf TDengine-server-2.0.20.12-Linux-x64.tar.gz
[root@hnbhbt ~]# cd TDengine-server-2.0.20.12
[root@hnbhbt ~]# ./install.sh
1. 启动TDengine
[root@hnbhbt ~]# systemctl start taosd
2. 检查TDengine状态
[root@hnbhbt ~]# systemctl status taosd
3. 输入以下命令进入TDengine命令行
taos
出现如下显示后表示进入成功
Welcome to the TDengine shell from Linux, Client Version:2.0.20.12
Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.
taos>
卸载: 需要手动删除配置文件以及日志
[root@hnbhbt ~]# sudo rm -rf /var/log/taos/
[root@hnbhbt ~]# sudo rm -rf /var/lib/taos/
[root@hnbhbt ~]# sudo rm -rf /etc/taos/taos.cfg
数据建模
表设计
-- 创建数据库
create database db_transfer_platform keep 730 replica 3;
-- 使用数据库
use db_transfer_platform;
-- 创建超表
create stable if not exists s_dust_history_data(ts timestamp,measured_value double,id int)tags(device_code nchar(30),channel_number nchar(30),signal_code nchar(30),status bool);
-- 删除超表
drop stable if exists s_dust_history_data;
-- ts 时间戳;measured_value 测量值;id 平台主键;device_code 设备编号;channel_number 通道序号;signal_code 信号编号;status 在线状态
数据插入
-- example:创建子表,插入数据,查询数据
-- 子表名称[监测信号_设备编号] eg pm_25_1003055表示设备编号为1003055的pm2.5的监测表
create table if not exists eg_pm_25_1003055 using s_dust_history_data tags('1003055','1','18113001',true);
create table if not exists eg_pm_10_1003055 using s_dust_history_data tags('1003055','2','18114001',false);
insert into eg_pm_25_1003055 (ts,measured_value,id) values("2021-07-29 21:43:22",7.0,123);
insert into eg_pm_10_1003055 (ts,measured_value,id) values("2021-07-29 21:43:22",6.0,124);
insert into eg_pm_25_1003055 (ts,measured_value,id) values("2021-07-29 21:43:22",9.0,123);
注:
1.全列模式写入速度会远快于指定列,建议尽可能采用全列写入方式
2.批量插入数据,写入速度更快(多支持同时插入32000条左右,和SQL长度有关)
3.对于重复的数据,忽略后面插入的数据
数据查询
select * from s_dust_history_data where ts > '2021-07-29 00:00:00' and ts < '2021-07-30 00:00:00' and signal_code = '18113001';
Spring Boot整合TDengine
当用户需要查询工地设备扬尘数据时,扬尘数据将通过定时任务从第三方接口中定时拉取保存至我们系统的数据库。由于扬尘数据的量较大,为千万甚至上亿级别,而系统配置相关数据的数据量较小,因此我们选择将扬尘数据和系统配置数据分离——扬尘数据使用TDengine进行存储,系统配置数据采用MySQL进行存储。
本文使用MybatisPlus作为持久层框架,同时接入TDengine和MySQL,做双数据源配置。下文中将重点讲述TDengine,MySQL相关内容将省略。
taos-jdbcdriver的选择
<dependency>
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>2.0.22</version>
<scope>runtime</scope>
</dependency>
双数据源配置
spring:
datasource:
dynamic:
druid:
initial-size: 10
min-idle: 10
max-active: 100
max-wait: 60000
test-while-idle: false
primary: td-engine
strict: false
datasource:
td-engine:
driver-class-name: com.taosdata.jdbc.TSDBDriver
url: jdbc:TAOS://address:port/dbname
username: dbusername
password: dbpassword
mysql:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ...
username: ...
password: ...
代码编写
Mapper
a. 创建Tags
<insert id="createTags" parameterType="TagsEntity">
create table if not exists #{tags名称}
using 超级表名称 tags
(#{tagsColumn1Value},
...
#{tagsColumnNValue})
</insert>
b. Tags插入单条数据
<insert id="insert" parameterType="TagsEntity">
insert into #{tags名称}
(#{tagsColumn1},
...
#{tagsColumnN})
values
(#{tagsColumn1Value},
...
#{tagsColumnNValue})
</insert>
<insert id="batchInsert" parameterType="TagsEntity">
insert into #{tags名称}
values
<foreach collection="list" item="data">
(#{data.tagsColumn1Value},
...
#{data.tagsColumnNValue})
</foreach>
</insert>
JavaBean
@Data
@TableName(tbname)
public class SuperTableEntity {
private String colunm1;
...
}
【问题一】在编写完代码后尽管查询不会出错,但插入和创建tags会发生错误,后来发现此处是DNS解析异常,由于TDengine配置了FQDN,因此应该在hosts中配置映射关系,之后才能进行正常的插入和创建操作。
【问题二】在进行第三方数据同步时,由于次是同步历史数据,因此插入TDengine的数据量较大。尽管TDengine本身支持的全列模式写入已经提升了不少效率,但如果代码中的批量插入继续使用普通for循环,插入效率仍然较低,这里可以通过切割数据和多线程的方式进行实现。
private void runner(List<Entity> list, int dealSize) throws Exception {
if (!CollectionUtils.isEmpty(list)) {
//数据总的大小
int count = list.size();
//每个线程数据集
List<Entity> threadList = null;
//线程池
int runSize = (count / dealSize) + 1;
ThreadPoolExecutor executor = new ThreadPoolExecutor(
runSize,
350,
30L, TimeUnit.SECONDS,
new SynchronousQueue<>());
CountDownLatch countDownLatch = new CountDownLatch(runSize);
for (int i = ; i < runSize; i++) {
//计算每个线程执行的数据
int startIndex = (i * dealSize);
if ((i + 1) == runSize) {
threadList = list.subList(startIndex, count);
} else {
int endIndex = (i + 1) * dealSize;
threadList = list.subList(startIndex, endIndex);
}
//TODO 这里写自己的线程任务
executor.execute(myThread);
}
//计数
countDownLatch.await();
//关闭线程池
executor.shutdown();
}
}
TDengine数据迁移
文档请参考:https://www.taosdata.com/blog/2020/03/09/1334.html
DUMP命令帮助信息
[root@hnbhbt ~]# taosdump --help
关键参数:
-h: 主机名称
-o: 导出文件路径
-i: 导入文件路径
-u: TDengine用户名
-p: TDengine密码
-A: 导出所有数据库的数据
-B: 导出指定数据库(可选多个数据库)
-S: 开始时间时间戳
-E: 结束时间时间戳
-T: 指定导出数据时,启动的线程数。建议设置成机器上core的2倍
1. 数据导出
[root@hnbhbt ~]# taosdump -h hostname -o /dump/>2. 数据导入
[root@hnbhbt ~]# taosdump -u username -p password -i ~/>【问题】此处在配置hostname时应该填写FQDN,如果不填写或者填写服务器IP,将会产生错误。
集群搭建 参考网址: 可扫描二维码下载相关附件
告警模块搭建 参考网址: 可扫描二维码下载相关附件
小结 应市质安站的监管要求以及蓝天办对空气污染治理的督查要求,市内所有工地的空气质量数据及噪音数据均需接入政府监管平台、纳入管理中。监控数据的特点就是时序、结构化、简单但量大,在处理这类数据上,TDengine可以说是量身定做。搭载TDengine后,监控数据上报后的实时展示、历史回溯都非常快,加上其本身轻量的特点,对于缩减项目开发运维成本也非常有帮助,完美满足了业务的需求。 来源 https://www.modb.pro/db/168850