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所组成。