Prometheus TSDB文件格式-index


Prometheus TSDB文件格式-index

存儲目錄

如下所示為Prometheus/TSDB存儲目錄結構:

drwxrwxr-x 3 service service 4096 Nov  9 12:08 01EPNJJA12FXV9YDYM3MBNE3HP
drwxrwxr-x 3 service service 4096 Nov 10 10:10 01EPQY3Z6AJ700B9DVFWSG0FSD
drwxrwxr-x 3 service service 4096 Nov 11 05:26 01EPSZZJ29EQZ9EQ1Z15EGGRJM
drwxrwxr-x 3 service service 4096 Nov 11 15:30 01EPV3C56BA53YZ4H28PQHBWQV
drwxrwxr-x 3 service service 4096 Nov 11 16:30 01EPV6T1RWCFQ6T4RVGAN2G7BG
drwxrwxr-x 3 service service 4096 Nov 11 17:11 01EPV8V50SMAJ617XQKWZ344HD
drwxrwxr-x 3 service service 4096 Nov 11 17:30 01EPVA7WJ5DXTV6FR06VJ0CT40
-rw------- 1 service service    7 Dec 13  2019 lock
-rw-rw-r-- 1 service service  200 Sep 26  2019 schema
drwxrwxr-x 2 service service 4096 Nov 11 17:42 wal

其中類似'01EPVA7WJ5DXTV6FR06VJ0CT40'的目錄為其中一個block。如下所示為block的目錄結構:

drwxrwxr-x 2 service service      4096 Nov 11 17:30 chunks
-rw-rw-r-- 1 service service 104684896 Nov 11 17:30 index
-rw-rw-r-- 1 service service       302 Nov 11 17:30 meta.json
-rw-rw-r-- 1 service service         9 Nov 11 17:30 tombstones

其中meta.json文件描述概要信息,一看就懂,不必多言:

{
	"ulid": "01EPVA7WJ5DXTV6FR06VJ0CT40",
	"minTime": 1605081600,
	"maxTime": 1605085200,
	"stats": {
		"numSamples": 1359295562,
		"numSeries": 441979,
		"numChunks": 11207472
	},
	"compaction": {
		"level": 1,
		"sources": [
			"01EPVA7WJ5DXTV6FR06VJ0CT40"
		]
	},
	"version": 2,
	"numChunkFile": 3
}

其中index文件用於定位和查詢指標數據,它是本文的主角。

index磁盤格式

首先,聲明一下index磁盤格式不等於index到內存里的格式,當然也差不太多。
如下所示為每個block目錄下面必有的index文件磁盤格式,index以TOC(table of contents)目錄表作為結尾。
TOC也作為index文件的入口:總是從文件尾部倒數N個字節讀取TOC開始干活。

┌────────────────────────────┬─────────────────────┐
│ magic(0xBAAAD700) <4b>     │ version(1) <1 byte> │
├────────────────────────────┴─────────────────────┤
│ ┌──────────────────────────────────────────────┐ │
│ │                 Symbol Table                 │ │
│ ├──────────────────────────────────────────────┤ │
│ │                    Series                    │ │
│ ├──────────────────────────────────────────────┤ │
│ │                 Label Index 1                │ │
│ ├──────────────────────────────────────────────┤ │
│ │                      ...                     │ │
│ ├──────────────────────────────────────────────┤ │
│ │                 Label Index N                │ │
│ ├──────────────────────────────────────────────┤ │
│ │                   Postings 1                 │ │
│ ├──────────────────────────────────────────────┤ │
│ │                      ...                     │ │
│ ├──────────────────────────────────────────────┤ │
│ │                   Postings N                 │ │
│ ├──────────────────────────────────────────────┤ │
│ │               Label Offset Table             │ │
│ ├──────────────────────────────────────────────┤ │
│ │             Postings Offset Table            │ │
│ ├──────────────────────────────────────────────┤ │
│ │                      TOC                     │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘

上述主要部分(section)之間,在寫入index時會追加一些padding字節用於對齊,在讀取時,需要跳過那些不在len里的值為0的padding字節。
大部分section都以len字段開始,len指定了該section有效的字節數,在這些有效數據之后,追加了一個checksum,它基於len的有效數據進行CRC32計算。

Symbol Table 字符串符號表

Symbol Table保存了所有sereis的label用到的字符串,並做了排序和去重。在后續的section中,將通過引用字符串的序號,達到降低index空間的目的。
Symbol Table包含一個序列的字符串條目,每個條目包括一個字符串原始字節的長度(len)和字符串實際字節兩個部分。字符串的格式是UTF-8,並且按字典序升序排序,通過條目序列的索引號對其進行引用。

┌────────────────────┬─────────────────────┐
│ len <4b>           │ #symbols <4b>       │
├────────────────────┴─────────────────────┤
│ ┌──────────────────────┬───────────────┐ │
│ │ len(str_1) <uvarint> │ str_1 <bytes> │ │
│ ├──────────────────────┴───────────────┤ │
│ │                . . .                 │ │
│ ├──────────────────────┬───────────────┤ │
│ │ len(str_n) <uvarint> │ str_n <bytes> │ │
│ └──────────────────────┴───────────────┘ │
├──────────────────────────────────────────┤
│ CRC32 <4b>                               │
└──────────────────────────────────────────┘

Series 時序數據索引表

該section包含了所有的series時序數據,包括sereis的label sets和其block內的chunks信息,series按label sets的字典序排序。
每個series按16字節對齊,series的ID=offset/16,后面section通過ID對該series進行引用。因此series的ID列表和sereis按字典序排序后的列表一一對應。

┌───────────────────────────────────────┐
│ ┌───────────────────────────────────┐ │
│ │   series_1                        │ │
│ ├───────────────────────────────────┤ │
│ │                 . . .             │ │
│ ├───────────────────────────────────┤ │
│ │   series_n                        │ │
│ └───────────────────────────────────┘ │
└───────────────────────────────────────┘

每個sereis section以len開始,以CRC32結尾。數據區首先是一個8字節數值標識labels的個數,然后是所有的labels,每個label包括name和value的ID號(對Symbol Table的引用)。該series的labels對按字典序排序。
緊隨label表格之后是對chunk的索引表,首先是一個8字節數值標識chunk的個數,然后是所有的chunks,每個chunk條目包括:chunk的最小時間mint和最大時間maxt,以及一個8字節數值指向chunk文件的位置position。mint即該series在該chunk里第一個sample的時間戳,maxt即該series在該chunk里最后一個sample的時間戳。
只有第一個mint保存的是原始時間戳值,后續的maxt以及后續chunk條目里的mintmaxt都是通過與前一個計算的差值進行保存。同樣的差值編碼也用於chunk條目的positon數值存儲。

┌──────────────────────────────────────────────────────────────────────────┐
│ len <uvarint>                                                            │
├──────────────────────────────────────────────────────────────────────────┤
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │                     labels count <uvarint64>                         │ │
│ ├──────────────────────────────────────────────────────────────────────┤ │
│ │              ┌────────────────────────────────────────────┐          │ │
│ │              │ ref(l_i.name) <uvarint32>                  │          │ │
│ │              ├────────────────────────────────────────────┤          │ │
│ │              │ ref(l_i.value) <uvarint32>                 │          │ │
│ │              └────────────────────────────────────────────┘          │ │
│ │                             ...                                      │ │
│ ├──────────────────────────────────────────────────────────────────────┤ │
│ │                     chunks count <uvarint64>                         │ │
│ ├──────────────────────────────────────────────────────────────────────┤ │
│ │              ┌────────────────────────────────────────────┐          │ │
│ │              │ c_0.mint <varint64>                        │          │ │
│ │              ├────────────────────────────────────────────┤          │ │
│ │              │ c_0.maxt - c_0.mint <uvarint64>            │          │ │
│ │              ├────────────────────────────────────────────┤          │ │
│ │              │ ref(c_0.data) <uvarint64>                  │          │ │
│ │              └────────────────────────────────────────────┘          │ │
│ │              ┌────────────────────────────────────────────┐          │ │
│ │              │ c_i.mint - c_i-1.maxt <uvarint64>          │          │ │
│ │              ├────────────────────────────────────────────┤          │ │
│ │              │ c_i.maxt - c_i.mint <uvarint64>            │          │ │
│ │              ├────────────────────────────────────────────┤          │ │
│ │              │ ref(c_i.data) - ref(c_i-1.data) <varint64> │          │ │
│ │              └────────────────────────────────────────────┘          │ │
│ │                             ...                                      │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────────────┤
│ CRC32 <4b>                                                               │
└──────────────────────────────────────────────────────────────────────────┘

注:每個block里會有多個chunk,每個series條目針對每個chunk都有且只有一個位置索引,由此也可以知道單個series在同一個chunk里的數據是連續存儲的。

Label index 標簽索引表

Label索引表保存了每個label name對應的values列表,可用於/api/v1/label/{name}/values接口快速查詢。
每個Label索引section同樣以len開始,以CRC32結束。數據區首先是字段name標識label name,然后是字段entries標識label下面的value個數,他們都是4字節大小。
隨后是所有的label value,每個value都是4字節,和name一樣,都是對Symbol Table的字符串的引用ID。value列表按字典序升序排序。

┌───────────────┬────────────────┬────────────────┐
│ len <4b>      │ #names <4b>    │ #entries <4b>  │
├───────────────┴────────────────┴────────────────┤
│ ┌─────────────────────────────────────────────┐ │
│ │ ref(value_0) <4b>                           │ │
│ ├─────────────────────────────────────────────┤ │
│ │ ...                                         │ │
│ ├─────────────────────────────────────────────┤ │
│ │ ref(value_n) <4b>                           │ │
│ └─────────────────────────────────────────────┘ │
│                      . . .                      │
├─────────────────────────────────────────────────┤
│ CRC32 <4b>                                      │
└─────────────────────────────────────────────────┘

如下例所示,為一個簡單的label name對應4個value:

┌────┬───┬───┬──────────────┬──────────────┬──────────────┬──────────────┬───────┐
│ 24 │ 1 │ 4 │ ref(value_0) | ref(value_1) | ref(value_2) | ref(value_3) | CRC32 |
└────┴───┴───┴──────────────┴──────────────┴──────────────┴──────────────┴───────┘

Label索引表每個name的長度不同,無法根據name快速定位到values在索引表的位置。該工作由Label offset table標簽偏移表完成,該表包含了每個label name對應在Label索引表中的位置。

Postings 倒排索引表

Postings表保存了每個label pair對應的series列表,這些series里都包含改label pair。series列表按ID遞增排序。
每個Postings section包含字段lenentriesseries列表和CRC32

┌────────────────────┬────────────────────┐
│ len <4b>           │ #entries <4b>      │
├────────────────────┴────────────────────┤
│ ┌─────────────────────────────────────┐ │
│ │ ref(series_1) <4b>                  │ │
│ ├─────────────────────────────────────┤ │
│ │ ...                                 │ │
│ ├─────────────────────────────────────┤ │
│ │ ref(series_n) <4b>                  │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ CRC32 <4b>                              │
└─────────────────────────────────────────┘

同樣,通過label pair快速索引到倒排索引表中位置的工作由Postings offset table倒排索引偏移表完成。

Label offset table 標簽偏移表

該表保存了一系列label偏移條目,每個條目包含label name和指向Label索引表的位置信息。

┌─────────────────────┬──────────────────────┐
│ len <4b>            │ #entries <4b>        │
├─────────────────────┴──────────────────────┤
│ ┌────────────────────────────────────────┐ │
│ │  n = 1 <1b>                            │ │
│ ├──────────────────────┬─────────────────┤ │
│ │ len(name) <uvarint>  │ name <bytes>    │ │
│ ├──────────────────────┴─────────────────┤ │
│ │  offset <uvarint64>                    │ │
│ └────────────────────────────────────────┘ │
│                    . . .                   │
├────────────────────────────────────────────┤
│  CRC32 <4b>                                │
└────────────────────────────────────────────┘

注:該表里的label name是直接保存了原始字符串,而不是對Symbol table的引用。

Postings offset table 倒排索引偏移表

該表保存了一系列label pair條目,每個條目包含label name/value pair和指向Postings表的位置信息。該表在index讀取時會部分導入到內存中。

┌─────────────────────┬──────────────────────┐
│ len <4b>            │ #entries <4b>        │
├─────────────────────┴──────────────────────┤
│ ┌────────────────────────────────────────┐ │
│ │  n = 2 <1b>                            │ │
│ ├──────────────────────┬─────────────────┤ │
│ │ len(name) <uvarint>  │ name <bytes>    │ │
│ ├──────────────────────┼─────────────────┤ │
│ │ len(value) <uvarint> │ value <bytes>   │ │
│ ├──────────────────────┴─────────────────┤ │
│ │  offset <uvarint64>                    │ │
│ └────────────────────────────────────────┘ │
│                    . . .                   │
├────────────────────────────────────────────┤
│  CRC32 <4b>                                │
└────────────────────────────────────────────┘

注:該表里的label name/value也是直接存儲了原始字符串,而不是對Symbol table的引用。

TOC 目錄表

TOC(table of contents)目錄表保存了指向各個表的位置信息,如果值為0,則表示對應的表不存在,對應的數據查詢返回為空。

┌─────────────────────────────────────────┐
│ ref(symbols) <8b>                       │
├─────────────────────────────────────────┤
│ ref(series) <8b>                        │
├─────────────────────────────────────────┤
│ ref(label indices start) <8b>           │
├─────────────────────────────────────────┤
│ ref(label offset table) <8b>            │
├─────────────────────────────────────────┤
│ ref(postings start) <8b>                │
├─────────────────────────────────────────┤
│ ref(postings offset table) <8b>         │
├─────────────────────────────────────────┤
│ CRC32 <4b>                              │
└─────────────────────────────────────────┘

參考

https://github.com/prometheus/prometheus/blob/master/tsdb/docs/format/index.md


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM