TDengine 资深研发分享解决思路,长查询不再成为系统性能瓶颈!

长查询问题指的是在数据库写入和查询并存的日常应用场景中,存在处理数据量大且耗时很长的查询长时间占用系统资源,导致写入可能被阻塞的问题。有时,查询代码对于资源释放函数调用的遗忘也可能以长查询问题的形式表现出来。如何在数据写入不被阻塞同时,保证长查询的正确进行是一个具有挑战性的问题。

尽管在绝大多数时序数据使用场景下,用户不太可能遇到这个问题,但一旦出现,也会让人头疼不已。为了解决这一问题,TDengine 研发团队一直致力于不断优化系统,提高查询性能和响应速度。本文将深入剖析这一挑战,并探讨如何应对和解决长查询问题,以提升 TDengine 在复杂查询场景下的表现。

在分析长查询问题之前,我们首先需要为大家普及一下 TDengine 的写入/查询并发机制。

数据写入/读取机制

Vnode 是 TDengine 中存储和查询数据的基本单元,这里主要介绍 Vnode 的写入/读取及并发机制。

数据写入机制

TDengine 资深研发分享解决思路,长查询不再成为系统性能瓶颈! - TDengine Database 时序数据库

  • 每个 Vnode 在创建时都会根据 DB 参数分配一定数量的内存
  • 这些内存在 Vnode 中被分为三个内存块
  • 每个 Vnode 只有一个线程写入
  • Vnode 在写入时,会从内存块的空闲列表 (free list) 中分配一个内存块(mem),供数据写入使用
  • 当内存块中数据写入超过一定量后,开始落盘(imem),同时分配一个新的内存块供数据写入使用
  • 当内存块全部用完,没有空闲内存块时,写入会被阻塞,一直等待有内存块释放出来
数据查询机制
  • 查询分多批次进行,每次返回部分数据,然后该查询等待下一次拉取数据的请求
  • 查询结果是内存(mem/imem)数据和硬盘数据合并的结果
  • 查询开始时,会先 take snapshot,引用(ref) mem/imem 以及硬盘文件
  • 查询结束时,unref mem/imem,如果内存块的引用计数变为 0,则内存块被回收到空闲链表中

TDengine 资深研发分享解决思路,长查询不再成为系统性能瓶颈! - TDengine Database 时序数据库

长查询问题

时序数据绝大部分查询持续时间都比较短,如查询表/超级表的最后一条记录、做 count 或 sum 类的聚合查询等。这类查询持续时间较短,对于 mem/imem 的占用时间也较短,查询很快会释放 MemTable 供 Vnode 回收再次利用,从而不影响写入的进行。但是,如果存在一个持续时间很长的查询,如超过 1 小时或 1 天的查询,这时候就会出现此类问题。当然,只有一个长查询的情况下,问题也不大,因为 Vnode 的内存池默认被分成了 3 个内存块,一个长查询最多占用两个内存块,还剩余一个内存块可以用来进行持续写入。但是如果存在多个长查询,Vnode 中的所有内存块都可能被长时间占用,无法进行回收,从而导致写入停止的情况。

另外,如果查询部分的代码存在 BUG,忘记关闭查询句柄,也会导致 mem/imem 被长期占用,阻塞写入。这个问题在 TDengine 订阅和流计算功能中曾经就出现过。

TDengine 资深研发分享解决思路,长查询不再成为系统性能瓶颈! - TDengine Database 时序数据库

长查询问题解决方案

我们需要一个方案,可以在长查询大量存在、或用户应用代码有问题没有及时关闭查询句柄、甚至产品代码有问题的情况下,也能达到既不阻塞写入且不让长查询失败。该方案如下:

  1. 查询在获取数据快照时,将查询句柄注册到它所占用的内存块上,同时注册一个 reseek 函数
  2. 当查询结束关闭句柄时,该查询将句柄从它所占用的所有内存块上注销
  3. 当写入发现没有可用内存块时,尝试回收已经 COMMIT 但是仍旧被查询占用的最老的内存块
  4. 写入线程回收内存块时,遍历所有注册在该内存块上的注册句柄,调用 reseek 函数
  5. reseek 函数会尝试锁查询句柄,如果锁句柄成功,则将查询句柄设置为 RESEEK 状态,同时将查询的状态保存下来并 untake snapshot,归还占用的所有内存块
  6. 查询线程在查询活跃周期开始时锁查询句柄,然后检查是否为 RESEEK 状态,如果为 RESEEK 状态,重新 take snapshot,并根据保存的查询状态,恢复各种查询变量,接着进行查询

从上述方案中我们可以看到:

  1. 写入在发现内存不足的条件下,可以主动回收非激活状态的查询占用的内存块,从而不会长时间阻塞写入
  2. 长查询在写入回收其所占用的内存块后,可以根据自己保存的查询状态,重新 take snapshot,继续查询,从而不会让长查询失败

TDengine 资深研发分享解决思路,长查询不再成为系统性能瓶颈! - TDengine Database 时序数据库

TDengine 资深研发分享解决思路,长查询不再成为系统性能瓶颈! - TDengine Database 时序数据库

答疑解惑

Q:如何解决死锁问题?

A:在写入回收内存块时,需要遍历查询句柄注册链表,因此需要对链表进行加锁操作,即需要锁定链表的锁。在调用 reseek 回调时,也需要锁定查询句柄的锁。这样就存在写入线程出现 lock(mutex_list)–>lock(mutex_qhandle) 的情况。而在查询结束时,需要将句柄从注册链表中移除,导致出现 lock(mutex_qhandle)–>lock(mutex_list) 的情况。如果两个线程不按照相同的顺序对两个锁进行加锁,就会产生死锁的问题。

为了解决这个问题,可以采用以下优化方案:

  1. 使用trylock替代lock:对于写入回收调用 reseek 函数的场景,可以尝试使用 trylock 而不是直接使用 lock 来获取查询句柄的控制权。通过 trylock 尝试获取锁,可以避免线程因等待锁而被阻塞,从而减少死锁的风险。
  2. 多次尝试机制:在使用 trylock 的基础上,可以结合多次尝试的机制。如果一次 trylock 未成功获取锁,可以进行多次尝试,直至成功获取锁或达到尝试次数上限为止。这样能够增加获取锁的机会,降低死锁风险。
Q:长查询会不会一直被写入 reseek,从而导致查询一直恢复?

A:不会存在这种情况。查询在每次打开句柄时,会给一个版本号,这个版本号是已经写入 Vnode 中的最新数据的版本号,查询只能看到版本号小于等于该版本号的数据。当 take snapshot 时,会根据 mem/imem 中的数据是否被查询版本号覆盖而决定 mem/imem 是否被该查询引用。随着数据的写入,新的 mem/imem 中的数据肯定都大于该查询创建时给的版本号,因此,新的 mem/imem 不会被长查询引用。这样一来,一个长查询最多会被写入 RESEEK 两次。

TDengine 资深研发分享解决思路,长查询不再成为系统性能瓶颈! - TDengine Database 时序数据库

以上就是 TDengine 资深研发人员对解决长查询问题进行的深入探讨。如果你还有关于查询的更多问题想要讨论或交流,欢迎添加小T vx:tdengine 寻求帮助,也可以在下方留言区进行相关评论,静待回复即可~


了解更多 TDengine Database 的具体细节,可在GitHub上查看相关源代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/438432.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一家新店怎么快速出体验分?教大家一个简单好用的方法,建议收藏

大家好,我是电商花花。 在现在直播电商时代,抖音电商已经成为了一种新兴的商业模式,在抖音小店的项目上,店铺体验分成为了抖音小店能否成功的一个关键因素之一。 店铺的体验分越高,我们店铺的权重才会更高&#xff0…

基于springboot+vue的在线远程考试系统

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

前端如何上传图片给后台?如何传递 multipart/form-data 类型的数据?图片大小、格式检查?

1. 如何上传图片? 图片上传需要传二进制流,请求头的 content-type 类型需为 multipart/form-data,传递的格式如下图所示 前后端交互通常为: 先调用接口上传二进制流图片然后再上传表单其他内容(第一步通常会返回后台…

Python语言基础与应用-北京大学-陈斌-P32-31-计算和控制流-上机练习:创建并调用函数-字符集合的并集-上机代码

Python语言基础与应用-北京大学-陈斌-P32-31-计算和控制流-上机练习&#xff1a;创建并调用函数-字符集合的并集-上机代码 本文环境&#xff1a; win10 Thonny4.1.4 # 函数训练字符集合的并集 def my_union(str1,str2):list1 []list2 []i 0 while i < len(str1):lis…

python_读取txt文件绘制多条曲线

读取txt文件&#xff0c;将匹配条件的多列绘制成曲线展示&#xff1a; import matplotlib.pyplot as plt import re from datetime import datetime from pylab import mplmpl.rcParams["font.sans-serif"] ["SimHei"] # 设置显示中文字体 mpl.rcParam…

[LeetCode][8]【学习日记】实现字符串转换整数 (atoi)函数

题目 8. 字符串转换整数 (atoi) 请你来实现一个 myAtoi(string s) 函数&#xff0c;使其能将字符串转换成一个 32 位有符号整数&#xff08;类似 C/C 中的 atoi 函数&#xff09;。 函数 myAtoi(string s) 的算法如下&#xff1a; 读入字符串并丢弃无用的前导空格检查下一个字…

3.7 day2 Free RTOS

使用ADC采样光敏电阻数值&#xff0c;如何根据这个数值调节LED灯亮度。2.总结DMA空闲中断接收数据的使用方法 while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */adc_value HAL_ADC_GetValue(&hadc);TIM3->CCR3 adc_value * 999 / 4095;printf("%d …

hadoop伪集群部署教程

文章目录 前言一、安装准备1. 安装条件2. 安装jdk3. 配置本节点免密登录 二、安装hadoop1. 下载并解压hadoop2. 设置环境变量2.1 设置hadoop安装目录环境变量2.2. 设置hadoop的root用户环境变量 3. 修改配置文件3.1 修改 etc/hadoop/hadoop-env.sh 文件3.2 修改 etc/hadoop/cor…

【Unity】【VR开发】用控制器摇杆改变Canvas的大小和位置

【背景】 做一个VR投屏工具,希望能够用右手控制器的摇杆,前后控制Canvas距离,左右控制Canvas大小。 【分析】 需要解决几个问题: 获取摇杆在横纵轴方向上的输入值需要通过合适的Event触发改变Canvas大小和距离的函数写具体的Canvas改变大小和距离的功能【技术选型】 VR…

eNSP | OSPF 协议来模拟和测试路由器之间的动态路由配置

一、拓扑结构的搭建 &#xff08;一&#xff09;PC1&#xff1a;IP如下图所示 注意&#xff1a; 1.网关地址一定要和所指示的接口IP相同 2.配置完PC1IP后&#xff0c;点击下面应用 &#xff08;二&#xff09;PC2&#xff1a;同pc1 二、IP地址的配置 &#xff08;一&#x…

什么是单点登录(SSO)前端用 iframe 实现单点登录 超详细说明!!

目录 什么是单点登录&#xff1f; 使用 iframe 实现单点登录 什么是单点登录&#xff1f; 单点登录的英文名叫做&#xff1a;Single Sign On&#xff08;简称SSO&#xff09;。 单点登录是一种身份验证过程&#xff0c;允许用户通过一次登录验证即可访问多个应用程序或服务…

华清远见作业第四十四天——FreeRTOS(第二天)

总结DMA空闲中断接收数据的使用方法 开启DMA接收 在主函数中以DMA空闲中断的方式接收数据的函数&#xff1a;HAL_UARTEx_ReceiveToIdle_DMA 然后调用空闲中断回调函数 切记/每次接收到数据都需要重新开启接收数据的函数。 DMA的作用 DMA是直接内存访问&#xff0c;使用DMA可…

Threejs着色器(GPU)编程——感温管网

管网,作为支撑现代城市运转的重要基础设施,是隐藏在地面之下的庞大工程网络。这些管网如同城市的血脉,负责输送各种必要的资源,如水源、热力、燃气等,同时排除废水和其他废弃物。然而,由于其位于地下,人们往往难以直接感知其存在和运行状态。为了保障这些地下管网的安全…

CLion 配置 Qt 开发环境

文章目录 CLion 配置 Qt 开发环境环境说明基本配置1. 创建Qt项目2. 设置CLion工具链3. 配置外部工具 一些问题的补充 CLion 配置 Qt 开发环境 环境说明 操作系统&#xff1a;Windows 10 CLion版本&#xff1a;2023.3.4 CMake版本&#xff1a;3.27.7 Qt6版本&#xff1a;6.6…

【SpringBoot】-- 实现本地文件/图片上传到服务器生成url地址

在java项目中你可能会有以下需求&#xff1a;用户上传本地图片&#xff0c;然后展示在网页上。本篇文章将使用阿里云oss实现上传图片到oss&#xff0c;oss生成url。 一、准备工作 首先进入阿里云&#xff0c;按如下操作 进入创建页面&#xff0c;修改读写权限为公共读 然后进…

unity学习(50)——服务器三次注册限制以及数据库化角色信息5--角色信息数据库化收尾

上一节内容结束后确实可以写入文件了&#xff0c;但还有两个问题&#xff1a; 1.一个是players.txt中&#xff0c;每次重启服务器&#xff0c;当注册新账号创建角色时&#xff0c;players.txt之前内容都会清空。 2.players.txt之前已经注册3次的账号&#xff0c;新注册的角色…

P2241 统计方形(数据加强版) python解法

求n*m网格内矩形的数目 - tenos - 博客园 (cnblogs.com) 法一&#xff08;题解推规律暴力枚举得到&#xff09;&#xff1a; n,mmap(int,input().split()) sqr,rec0,0 #正方形和长方形个数 #以长宽做循环&#xff0c;每次求n*m大小的矩形的个数 #题解是从0开始的&#xff0c;我…

软件测试相关概念和bug的相关总结

文章目录 什么是测试什么是需求测试用例(CASE)什么是BUG软件的生命周期开发模型瀑布模型螺旋模型增量模型和迭代模型 敏捷测试模型v模型W模型(双V模型) 软件测试的生命周期如何描述一个bugbug的级别bug的生命周期.产生争执怎么办 什么是测试 测试是测试人员用来检验软件的实际运…

分时段计费点电能表 削峰填谷

分时电价机制分为峰谷电价机制、季节性电价机制等。峰谷电价机制是将一天划分为高峰、平段、低谷&#xff0c;季节性电价机制是将峰平谷时段划分进一步按夏季、非夏季等作差别化安排&#xff0c;对各时段分别制定不同的电价水平。 国家发展改革委有关负责人指出&#xff0c;此…

SSD LDPC软错误探测方案解读

上一篇文档中,基于SSD LDPC(Low-Density Parity-Check Codes)原理背景和纠错能力作了简单的介绍。 扩展阅读: 关于SSD LDPC纠错能力的基础探究 浅析LDPC软解码对SSD延迟的影响 本篇结合SMI发布的研究成果,通过SSD控制内部LDPC更底层的架构,来解读如何增强软错误探测能力…