prometheus tsdb block

367 阅读2分钟

block

head块压缩到内存中就变成了block。

一个block包括四个文件

  • chunk存储数据
  • index存储索引
  • tombstone存储删除的series
  • meta存储元信息

index

对于索引。我们知道通常很多series的大部分tag是相同的。

也就是说:

  • 大部分tag指向相同的series
  • series的tag的name和value有很多是重复的

因此:

  • posting表示seires列表,posting offset table存储一个tag加postring的偏移量,这样那些指向相同series的tag就可以复用
  • symbol列表存储不重复的tag k,v。series通过存储symbol的索引,复用tag。

series

每一个block的一个series都会生成以下数据。

  • 该series所有label的k,v。这里通过值存储索引来减少内存
  • 该series指向的chunkref以及mint和maxt:通过保存差值来压缩数据。
┌──────────────────────────────────────────────────────┐
│ 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>                                           │
└──────────────────────────────────────────────────────┘

symbol

所有label的k,v对经过去重后,写入symbol。

然后这里的数据又被series使用。

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

posting offset table

对于label的每个k,v对,写入在posting 中的索引。

其实就是唯一的一个tag。

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

postings

posting保存所有series的ref。

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

memposting

memposting表示内存中的posting。

用一个map表示,其中map的key为tag的name。

map的value又是一系列的series,其中新map的key是tag的value,value是此tag的k,v对所指向的一系列的series。

type MemPostings struct {
    mtx     sync.RWMutex
    m       map[string]map[string][]storage.SeriesRef
    ordered bool
}
​

memposting有个非常有意思的叫做ensureordery。

就是会确保每一个tag的seriesref都是有序的。

因此会开runtime.GOMAXPROCS个goroutine去执行sort的job。

job就是如下,遍历m,每遇到1024个k,v对就生成一个job。

[][]storage.SeriesRef
// EnsureOrder ensures that all postings lists are sorted. After it returns all further
// calls to add and addFor will insert new IDs in a sorted manner.
func (p *MemPostings) EnsureOrder() {

每一个tag的id已经拍好序是非常重要的。

比如我们搜索以下tag的交集的时候。就可以通过两个指针,o(n)的搜索,其中浪费的空间为o(1)。

__name__="requests_total"   ->   [ 9999, 1000, 1001, 2000000, 2000001, 2000002, 2000003 ]
     app="foo"              ->   [ 1, 3, 10, 11, 12, 100, 311, 320, 1000, 1001, 10002 ]
​
             intersection   =>   [ 1000, 1001 ]

tombstone

tombstone由删除的series以及删除的范围Mint和maxt所组成。