Prometheus TSDB

article/2025/9/1 21:07:50

TSDB 概述:
在这里插入图片描述
Head: 数据库的内存部分
Block: 磁盘上持久块,是不变的
WAL: 预写日志系统
M-map: 磁盘及内存映射

粉红色框是传入的样品,样品先进入Head中存留一会,然后到磁盘、内存映射中(蓝色框)。然后当内存映射块时间长到某点,就会作为持久块存在硬盘上,进一步一个个合并。
超出保留时间就会被删除。


Head的生命周期

(这里讨论的都是基于一个time series,同样适用于其他time series)
在这里插入图片描述
当样品存入时,chunk变活跃,红色块是我们唯一可以主动编写数据的单位。

将样品存入时,我们还会将其记录在WAL中,在机器崩溃时可以从中恢复数据。
在这里插入图片描述
默认chunkRange为120,如果2小时内,chunkRange都是120的满状态情况,就会新建一个chunk,在这篇博客里,我们默认抓取间隔为15s。所以从空chunk到满chunk需要30min.

黄色block是刚刚填充满的满chunk,红色块则是创建的新块。
在这里插入图片描述
在prometheus v2.19.0中,我们不会把所有块存在内存中。当新chunk建立,full chunk被放入磁盘,如果只存内存索引时就将full chunk存入磁盘的memory-mapped中。然后在我们需要时,用索引将chunk动态加载到内存中。
在这里插入图片描述
随着新样品不断进入,新的chunk被分割。
在这里插入图片描述
被放入磁盘及内存映射中
在这里插入图片描述
过了一段时间head如图示,我们认为红色chunk几乎满了,那么我们在head里存在3h的数据。(6个chunk,每个30min满)chunkRange3/2
在这里插入图片描述
当数据存储至chunkRange
3/2时,(2h时)就会压缩成一个恒久chunk。此时WAL被截断,创建一个checkPoint。
以上周而复始及为head的功能。

如果TSDB必须重新启动(优雅退出、突然),他将使用内存映射的chunk和WAL重放数据和事件,重新构建内存索引等。


WAL基础知识

当编写、修改、删除数据库的数据之前,事件首先被记录在WAL中,然后才进行相关操作。

在Prometheus TSDB中写入WAL

records类型

prometheus中存在三种wal类型:

  • Series 当一个新的series到达时记录一次,先将series写入Head,再写wal
  • Samples 先写wal,再写入Head,
  • Tombstones 用于记录删除特定series,soft delete

WAL截断

在上一篇中介绍过,当Head Block阶段时也同时截断wal,在实际实现时,由于写请求可以是随机的,因此要确定WAL段中样本的时间范围而不遍历所有记录比较困难,因此简化为直接删除2/3。

这里有个问题,series只存一次,在wal也一样,直接截断wal可能会丢失series,甚至依然是还在Head中的series,这里引入check point来处理改问题。

CheckPointing

假设截断的时间点是T,要实现保留series,需要遍历所有要删除的wal文件:

  • 删除所有不在Head中的series
  • 删除所有在时间T之前的samples
  • 删除所有在时间T之前的tombstones
  • 保留剩余的series、samples、tombstones到checkpoint.X文件
data
└── wal├── checkpoint.000002|   ├── 000000|   └── 000001├── 000003

从WAL恢复时,直接从最新的一个checkpoint.X文件开始,扫描X+1对应的WAL文件名;
WAL底层写入磁盘使用32KB page。


当一个chunk满了(120个sample或者2h)以后,会使用m-map(2)将其flush到disk中,其数据不在占用内存,索引依然保留在内存中。

写 chunks
从第1部分重新开始,当一个chunk已满时,我们剪切了一个新chunk,而较旧的chunk变得不可变,只能从中读取(下面的黄色块)。
在这里插入图片描述
而不是将其存储在内存中,我们将其刷新到磁盘并存储引用以供以后访问。
在这里插入图片描述
此刷新的chunk是磁盘中的内存映射chunk。不变性是最重要的因素,否则对于每个sample而言,重写压缩chunk的效率都太低。

File

这些chunks保留在其自己的目录中,称为chunks_head,其文件序列类似于WAL(除了以1开头)。例如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cDhNZkQZ-1636355505443)(/download/attachments/1195970022/image-1636352695839.png?version=1&modificationDate=1636352693244&api=v2)]
文件由8B的文件头和chunks数据组成:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ac2Cikgz-1636355505445)(/download/attachments/1195970022/image-1636352672901.png?version=1&modificationDate=1636352670327&api=v2)]

Chunks

┌─────────────────────┬───────────────────────┬───────────────────────┬───────────────────┬───────────────┬──────────────┬────────────────┐
| series ref <8 byte> | mint <8 byte, uint64> | maxt <8 byte, uint64> | encoding <1 byte> | len <uvarint> | data <bytes> │ CRC32 <4 byte> │
└─────────────────────┴───────────────────────┴───────────────────────┴───────────────────┴───────────────┴──────────────┴────────────────┘

series ref :是内存中某个的series索引的id,这里是为了方便后续宕机恢复时重建索引数据
mint,maxt:chunk时间戳
encoding :压缩编码方式
len :数据长度
data :压缩编码的数据

如何访问

内存中依然有每个chunks的地址(也叫ref,64位,前32位是文件号,后32位是文件内字节偏移)和mint、maxt。
在代码中看,每个chunks文件都是一个byte slice,当访问该byte slice时,mmap自动映射到磁盘中的文件。

series ref id ->[(ref,mint,maxt),(addr2,mint2,maxt2)…]-> mmap chunks

重启实例时重新生成HeadBlock

因为所有满了的chunk都被mmap到了磁盘目录chunks_head下面,所以在重建HeadBlock时,直接可以使用这些数据重建满chunks,然后再根据wal重建还没有满的chunks。
重建在磁盘中的满的mmap chunks只需要重建index(如上节所示map)即可;
重建wal中的未满的chunks就需要重建index和数据。

Mmap优点

  • 节省约15%~50%内存使用
  • 节省启动时间15%~30%,主要是不需要重建所有wal了

GC

tsdb定期截断HeadBlock为一个2h(default)的block,在截断时,也是内存gc的时刻,对于截断时间T之前的index都可以gc。


Block

磁盘上的Block可以认为是一个小型的db,自带了index和chunks data,其中chunks可以是多个文件。
每个Block用一个Universally Unique Lexicographically Sortable Identifier (ULID)唯一识别。
每个Block是不可变的数据文件,只能标记删除,不同block之间没有引用关系。
默认一个新生成的block是2h的数据,随着时间推移,多个2h block可以compate(merge)为一个更大的block。

block组成

meta.json (file): block元数据,json文件。
chunks (directory): chunks数据文件
index (file): 索引文件
tombstones (file): 删除标记文件

在这里插入图片描述

meta.json

meta记录当前block的ulid,chunks数量,samples数量,时间跨度,comapction等级等信息。

{"ulid": "01EM6Q6A1YPX4G9TEB20J22B2R","minTime": 1602237600000,"maxTime": 1602244800000,"stats": {"numSamples": 553673232,"numSeries": 1346066,"numChunks": 4440437},"compaction": {"level": 1,"sources": ["01EM65SHSX4VARXBBHBF0M0FDS","01EM6GAJSYWSQQRDY782EA5ZPN"]},"version": 1
}

chunks

chunks是一个目录,内部存放着多个有序排列的chunks文件,每个文件默认512MB,保存着所有chunks data。
此时的chunk格式发生了变化,具体如下:

┌───────────────┬───────────────────┬──────────────┬────────────────┐
│ len <uvarint> │ encoding <1 byte> │ data <bytes> │ CRC32 <4 byte> │
└───────────────┴───────────────────┴──────────────┴────────────────┘

相比HeadBlock mmap chunk格式,缺少了series ref、mint 和 maxt,这三个信息现在存入了index文件

index

index是一个倒排索引,index的实现比较常规,主要由以下几部分:

一个符号表,每个series中存一个特定符号的addr能节省内存
每个series有一个固定的series ID可以寻址,且每个series内包含在该block内对应的所有chunks地址信息和时间范围信息
基于单个字符的倒排索引,比如有两个series{a=“b1”, x=“y1”} 和 {a=“b2”, x=“y2”},字符a和x将各自都有一个索引指向这两个series,index(a)->[ref(series id1), ref(series id2)]
因为每个字符的索引slice可能很大,所以在实现上,做了一个二级index,字符a -> index(a) -> [ref(series id1), ref(series id2)]

在这里插入图片描述

Postings Offset Table :第一级index,存储每个label对(name,value)对应的Postings N
Postings N: 第二级index,存放一个label对应的所有series id
Series:各个Series信息,包含series ID,按id有序排列,每个series内包含在该block内对应的所有chunks地址信息和时间范围信息可以查找数据
Label Index 和 Label Offset Tabel 废弃了


query分为三种:

  • LabelNames() : 查询所有label names(直接循环遍历Posting Offset Table,获取所有的label name即可。)
  • LabelValues(name) : 查询指定label name对应的所有values(直接循环遍历Posting Offset Table,获取所有的label name与name一致的label value即可。)
  • Select([]matcher) : 返回符合matcher的series

Select([]matcher)

matcher用于选择出符合指定label name和label value的series,有以下4种:

  • labelName="" ,相等匹配
  • labelName!="" ,不相等匹配
  • labelName=~"",正则正匹配
  • labelName!~"" ,正则负匹配

匹配步骤:

  • 获得单个matcher匹配的所有series
  • 取交集

Postings Offset Table存放了所有label name和label value的组合,并且指向Postings N,Postings N包含了所有的series ID。
相等匹配:遍历Postings Offset Table,找到name和value都相等的项就可以获得对应的Postings,然后获得series
正则正匹配:需要遍历所有Postings Offset Table,找到所有符合的name和value项,然后也可以获得series
同理,负向匹配一样,但负匹配可能会匹配到大量数据,所以,不允许单个负匹配查询,必须结合一个相等或者正则正匹配才能使用负匹配。

然后,获取到所有单个matcher的Postings后,进行交集,获取最终的Postings,然后遍历Postings对应的series id,根据series id中的chunk addr和mint、 maxt取得数据返回。

最后,如果查询时间跨越多个block,那么应该单独查每个block,然后将结果merge。

Querying Head block

Head block在内存中建立了map[labelName]map[labelValue]postingsList结构的索引,可以直接查上述过程。

整理 (https://ganeshvernekar.com/blog/prometheus-tsdb-the-head-block/) 学习内容


http://chatgpt.dhexx.cn/article/X0R0oLUA.shtml

相关文章

TiDB体系结构之TiDB Server

TiDB体系结构之TiDB Server TiDB ServerTiDB Server主要组成模块SQL语句的解析和编译行数据与KV的转化SQL读写相关模块在线DDL相关模块TiDB的垃圾回收TiDB Server的缓存 TiDB Server TiDB Server的主要作用如下&#xff1a; 处理客户端连接SQL语句的解析和编译关系型数据与KV…

TSDB助力风电监控

各位小伙伴大家好&#xff0c;本期Jesse想再来跟大家聊聊TSDB的应用场景&#xff0c;在此也感谢尹晨所著的《时序数据库在风电监控系统中的应用》一文&#xff0c;其为我们探究TSDB在风电系统中的应用提供了重要的帮助。 本文仅代表个人观点&#xff0c;如有偏颇之处&#xff…

dbt-tidb 1.2.0 尝鲜

作者&#xff1a; shiyuhang0 原文来源&#xff1a; https://tidb.net/blog/1f56ab48 本文假设你对 dbt 有一定了解。如果是第一次接触 dbt&#xff0c;建议先阅读 官方文档 或 当 TiDB 遇见 dbt 本文中的示例基于官方维护的 jaffle_shop 项目。关于此项目的细节介绍&a…

为啥用 时序数据库 TSDB

前言 其实我之前是不太了解时序数据库以及它相关的机制的&#xff0c;只是大概知晓它的用途。但因为公司的业务需求&#xff0c;我意外参与并主导了公司内部开源时序数据库influxdb的引擎改造&#xff0c;所以我也就顺理成章的成为时序数据库“从业者”。 造飞机的人需要时刻…

Prometheus 学习之——本地存储 TSDB

Prometheus 学习之——本地存储 TSDB 文章目录 Prometheus 学习之——本地存储 TSDB前言一、TSDB 核心概念二、详细介绍1.block1&#xff09;chunks2&#xff09;index3&#xff09;tombstone4&#xff09;meta.json 2.WAL 总结 前言 Prometheus 是 CNCF 收录的第二个项目&…

阿里云IoT物模型上报数据流转到实例内TSDB

阿里云物联网平台上存储的数据最多为30天&#xff0c;为了能让数据永久保存下来&#xff0c;就需要把物联网平台的数据流转到其他的数据库&#xff0c;对于企业版实例&#xff0c;内部有一个实例内的时空数据库TSDB&#xff0c;正好可以利用。下边就介绍一下物联网平台的物模型…

使用TSDB自动检测时序数据的异常情况

本期Jesse就带大家来继续了解一下TSDB的应用问题&#xff0c;小伙伴们&#xff0c;让我们直接步入正题吧。 本文仅代表个人观点&#xff0c;如有偏颇之处&#xff0c;还请海涵&#xff5e; 现今&#xff0c;每天都有数千亿个传感器产生大量时序数据。公司收集大量数据使得分析…

TSDB 存储引擎介绍

本文介绍 DolphinDB 在2.0版本中新推出的存储引擎 TSDB。 1. OLAP 与 TSDB 适用的场景 OLAP 是 DolphinDB 在2.0版本之前的唯一存储引擎。数据表中每个分区的每一列存为一个文件。数据在表中的存储顺序与数据写入的顺序一致&#xff0c;数据写入有非常高的效率。 OLAP 引擎的…

TSDB与Blockchain

各位小伙伴们我们又见面了&#xff0c;伴随着区块链技术的推广&#xff0c;很多企业也在思考是否将其应用。其实TSDB与区块链有很多共通之处&#xff0c;本期Jesse就来和大家聊聊TSDB与区块链。本文参考了Nicolas Hourcard的文章“You Don’t Need a Blockchain, You Need a Ti…

FlashDB嵌入式数据库之TSDB数据存储解析

一、驱动层&#xff1a;SFUD&#xff08;Serial Flash Universal Driver&#xff09; 是一款开源的串行 SPI Flash 通用驱动库 二、中间层&#xff1a;FAL&#xff08;FLASH ABSTRACTION LAYER)&#xff09;FLASH 抽象层 三、应用层&#xff1a;FlashDB&#xff08;FlashDB 是一…

时间序列数据库 (TSDB)

参考文档&#xff1a;时间序列数据库 TSDB_时间序列数据库 TSDB-阿里云帮助中心 什么是时序数据库 时序数据是随时间不断产生的一系列数据&#xff0c;简单来说&#xff0c;就是带时间戳的数据。数据可能来自服务器和应用程序的指标、物联网传感器的读数、网站或应用程序上的…

TSDB在高速公路大数据平台的应用

好久没有跟大家聊TSDB的应用场景了&#xff0c;Jesse也在国庆期间进行了补课&#xff0c;今天就跟大家聊聊TSDB在高速公路大数据平台的应用。本文借鉴了郝建明、袁逸涛发表在《上海船舶运输科学研究生学报》的《基于时序数据库的高速公路数据集成平台》一文&#xff0c;感谢二位…

时序数据库(TSDB)

时序数据库&#xff08;TSDB&#xff09;是一种特定类型的数据库&#xff0c;主要用来存储时序数据。随着5G技术的不断成熟&#xff0c;物联网技术将会使得万物互联。物联网时代之前只有手机、电脑可以联网&#xff0c;以后所有设备都会联网&#xff0c;这些设备每时每刻都会吐…

TSDB数据库

目录 为什么需要时序数据库&#xff1a; 时间序列数据库的特点&#xff1a; 常见的时间序列数据库&#xff1a; 时间序列数据库存储&#xff1a; 时间序列数据库问题&#xff1a; 参考资料&#xff1a; 内容是在我球的docs上直接复制过来的&#xff0c;懒得写两份&#x…

关于时许数据库的相关名词解释

1 时序数据库TSDB 英文全称为 Time Series Database&#xff0c;提供高效存取时序数据和统计分析功能的数据管理系统。 2 时序数据&#xff08;Time Series Data&#xff09; 基于稳定频率持续产生的一系列指标监测数据。例如&#xff0c;监测某城市的空气质量时&#xff0c…

物联网平台搭建的全过程介绍(六)——物联网TSDB之基本知识及读写代码介绍

目录 一、TSDB基本知识 二、物联网平台数据流通架构 三、TSDB数据结构 1、TSDB数据包的组成 2、TSDB的另外两个相关概念 四、阿里云物联网平台实例内TSDB功能介绍 1、数据写入 &#xff08;1&#xff09;需要添加的依赖 &#xff08;2&#xff09;写入数据代码 2、数据…

ES6—简介

目录 一、概述 二、扩展&#xff1a;Babel转码器 三、拓展&#xff1a;编译打包 一、概述 概念 ES6全称ECMAScript 6.0&#xff0c;是Javascript语言的下一代标准&#xff0c;2015年6月正式发布。 注意&#xff0c;ES6既是一个历史名词&#xff0c;也是一个泛指&#xff0c;…

深入浅出ES6(一):ES6是什么

深入浅出ES6&#xff08;一&#xff09;&#xff1a;ES6是什么 作者 Jason Orendorff &#xff0c;译者 刘振涛 发布于 2015年6月5日 | http://www.infoq.com/cn/articles/es6-in-depth-an-introduction 我的阅读清单 编者按&#xff1a;ECMAScript 6离我们越来越近了&#…

[ 前端开发 ] 为什么要学习ES6?

ECMAScript 6 概念 ECMAScript 6 简称 ES6 为什么要学习ES6? ES6 是 JavaScript 的下一个版本标准&#xff0c;诞生于2015年6月份。ES6 的主要目的是为了解决 ES5 的先天不足。ES6 的终极目标是为了使 JavaScript 语言可以用来编写复杂的大型应用程序&#xff0c;成为企业…

前端基础之ES6

ES6 ES6简介 ES6实际上是一个泛指&#xff0c;泛指ES2015及后续版本 为什么使用ES6&#xff1f; 每一次标准的诞生都意味着语言的完善&#xff0c;功能的加强。JavaScript语言本身也有一些令人不满意的地方。 变量提升特性增加了程序运行时的不可预测性语法过于松散&#x…