偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Prometheus時(shí)序數(shù)據(jù)庫(kù)-磁盤中的存儲(chǔ)結(jié)構(gòu)

存儲(chǔ) 存儲(chǔ)軟件
Prometheus作為時(shí)序數(shù)據(jù)庫(kù),設(shè)計(jì)了各種文件結(jié)構(gòu)來(lái)保存海量的監(jiān)控?cái)?shù)據(jù),同時(shí)還兼顧了性能。只有徹底了解其存儲(chǔ)結(jié)構(gòu),才能更好的指導(dǎo)我們應(yīng)用它!

[[384167]]

前言

之前的文章里,筆者詳細(xì)描述了監(jiān)控?cái)?shù)據(jù)在Prometheus內(nèi)存中的結(jié)構(gòu)。而其在磁盤中的存儲(chǔ)結(jié)構(gòu),也是非常有意思的,關(guān)于這部分內(nèi)容,將在本篇文章進(jìn)行闡述。

磁盤目錄結(jié)構(gòu)

首先我們來(lái)看Prometheus運(yùn)行后,所形成的文件目錄結(jié)構(gòu)

 

在筆者自己的機(jī)器上的具體結(jié)構(gòu)如下:

  1. prometheus-data 
  2.     |-01EY0EH5JA3ABCB0PXHAPP999D (block) 
  3.     |-01EY0EH5JA3QCQB0PXHAPP999D (block) 
  4.         |-chunks 
  5.             |-000001 
  6.             |-000002 
  7.             ..... 
  8.             |-000021 
  9.         |-index 
  10.         |-meta.json 
  11.         |-tombstones 
  12.     |-wal 
  13.     |-chunks_head 

Block

一個(gè)Block就是一個(gè)獨(dú)立的小型數(shù)據(jù)庫(kù),其保存了一段時(shí)間內(nèi)所有查詢所用到的信息。包括標(biāo)簽/索引/符號(hào)表數(shù)據(jù)等等。Block的實(shí)質(zhì)就是將一段時(shí)間里的內(nèi)存數(shù)據(jù)組織成文件形式保存下來(lái)。

 

最近的Block一般是存儲(chǔ)了2小時(shí)的數(shù)據(jù),而較為久遠(yuǎn)的Block則會(huì)通過(guò)compactor進(jìn)行合并,一個(gè)Block可能存儲(chǔ)了若干小時(shí)的信息。值得注意的是,合并操作只是減少了索引的大小(尤其是符號(hào)表的合并),而本身數(shù)據(jù)(chunks)的大小并沒(méi)有任何改變。

meta.json

我們可以通過(guò)檢查meta.json來(lái)得到當(dāng)前Block的一些元信息。

  1.     "ulid":"01EY0EH5JA3QCQB0PXHAPP999D" 
  2.     // maxTime-minTime = 7200s => 2 h 
  3.     "minTime": 1611664000000 
  4.     "maxTime": 1611671200000 
  5.     "stats": { 
  6.         "numSamples": 1505855631, 
  7.         "numSeries": 12063563, 
  8.         "numChunks": 12063563 
  9.     } 
  10.     "compaction":{ 
  11.         "level" : 1 
  12.         "sources: [ 
  13.             "01EY0EH5JA3QCQB0PXHAPP999D" 
  14.         ] 
  15.     } 
  16.     "version":1 

其中的元信息非常清楚明了。這個(gè)Block記錄了2個(gè)小時(shí)的數(shù)據(jù)。

 

讓我們?cè)僬乙粋€(gè)比較陳舊的Block看下它的meta.json.

  1. "ulid":"01EXTEH5JA3QCQB0PXHAPP999D"
  2.  // maxTime - maxTime =>162h 
  3.  "minTime":1610964800000, 
  4.  "maxTime":1611548000000 
  5.  ...... 
  6.  "compaction":{ 
  7.      "level": 5, 
  8.      "sources: [ 
  9.          31個(gè)01EX...... 
  10.      ] 
  11.  }, 
  12.  "parents: [ 
  13.      {     
  14.          "ulid": 01EXTEH5JA3QCQB1PXHAPP999D 
  15.          ... 
  16.      } 
  17.      {     
  18.          "ulid": 01EXTEH6JA3QCQB1PXHAPP999D 
  19.          ... 
  20.      } 
  21.              {     
  22.          "ulid": 01EXTEH5JA31CQB1PXHAPP999D 
  23.          ... 
  24.      } 
  25.  ] 

從中我們可以看到,該Block是由31個(gè)原始Block經(jīng)歷5次壓縮而來(lái)。最后一次壓縮的三個(gè)Block ulid記錄在parents中。如下圖所示:

 

Chunks結(jié)構(gòu)

CUT文件切分

所有的Chunk文件在磁盤上都不會(huì)大于512M,對(duì)應(yīng)的源碼為:

  1. func (w *Writer) WriteChunks(chks ...Meta) error { 
  2.     ...... 
  3.     for i, chk := range chks { 
  4.         cutNewBatch := (i != 0) && (batchSize+SegmentHeaderSize > w.segmentSize) 
  5.         ...... 
  6.         if cutNewBatch { 
  7.             ...... 
  8.         } 
  9.         ...... 
  10.     } 

當(dāng)寫入磁盤單個(gè)文件超過(guò)512M的時(shí)候,就會(huì)自動(dòng)切分一個(gè)新的文件。

一個(gè)Chunks文件包含了非常多的內(nèi)存Chunk結(jié)構(gòu),如下圖所示:

 

圖中也標(biāo)出了,我們是怎么尋找對(duì)應(yīng)Chunk的。通過(guò)將文件名(000001,前32位)以及(offset,后32位)編碼到一個(gè)int類型的refId中,使得我們可以輕松的通過(guò)這個(gè)id獲取到對(duì)應(yīng)的chunk數(shù)據(jù)。

chunks文件通過(guò)mmap去訪問(wèn)

由于chunks文件大小基本固定(最大512M),所以我們很容易的可以通過(guò)mmap去訪問(wèn)對(duì)應(yīng)的數(shù)據(jù)。直接將對(duì)應(yīng)文件的讀操作交給操作系統(tǒng),既省心又省力。對(duì)應(yīng)代碼為:

  1. func NewDirReader(dir string, pool chunkenc.Pool) (*Reader, error) { 
  2.     ...... 
  3.     for _, fn := range files { 
  4.         f, err := fileutil.OpenMmapFile(fn) 
  5.         ...... 
  6.     } 
  7.     ...... 
  8.     bs = append(bs, realByteSlice(f.Bytes())) 
  9. 通過(guò)sgmBytes := s.bs[offset]就直接能獲取對(duì)應(yīng)的數(shù)據(jù) 

 

index索引結(jié)構(gòu)

前面介紹完chunk文件,我們就可以開始闡述最復(fù)雜的索引結(jié)構(gòu)了。

尋址過(guò)程

索引就是為了讓我們快速的找到想要的內(nèi)容,為了便于理解。筆者就通過(guò)一次數(shù)據(jù)的尋址來(lái)探究Prometheus的磁盤索引結(jié)構(gòu)??紤]查詢一個(gè)

  1. 擁有系列三個(gè)標(biāo)簽 
  2. ({__name__:http_requests}{job:api-server}{instance:0}) 
  3. 且時(shí)間為start/end的所有序列數(shù)據(jù) 

我們先從選擇Block開始,遍歷所有Block的meta.json,找到具體的Block

 

前文說(shuō)了,通過(guò)Labels找數(shù)據(jù)是通過(guò)倒排索引。我們的倒排索引是保存在index文件里面的。那么怎么在這個(gè)單一文件里找到倒排索引的位置呢?這就引入了TOC(Table Of Content)

TOC(Table Of Content)

 

由于index文件一旦形成之后就不再會(huì)改變,所以Prometheus也依舊使用mmap來(lái)進(jìn)行操作。采用mmap讀取TOC非常容易:

  1. func NewTOCFromByteSlice(bs ByteSlice) (*TOC, error) { 
  2.     ...... 
  3.     // indexTOCLen = 6*8+4 = 52 
  4.     b := bs.Range(bs.Len()-indexTOCLen, bs.Len()) 
  5.     ...... 
  6.     return &TOC{ 
  7.         Symbols:           d.Be64(), 
  8.         Series:            d.Be64(), 
  9.         LabelIndices:      d.Be64(), 
  10.         LabelIndicesTable: d.Be64(), 
  11.         Postings:          d.Be64(), 
  12.         PostingsTable:     d.Be64(), 
  13.     }, nil 

Posting offset table 以及 Posting倒排索引

首先我們?cè)L問(wèn)的是Posting offset table。由于倒排索引按照不同的LabelPair(key/value)會(huì)有非常多的條目。所以Posing offset table就是決定到底訪問(wèn)哪一條Posting索引。offset就是指的這一Posting條目在文件中的偏移。

 

Series

我們通過(guò)三條Postings倒排索引索引取交集得出

  1. {series1,Series2,Series3,Series4} 
  2. ∩ 
  3. {series1,Series2,Series3} 
  4. ∩ 
  5. {Series2,Series3} 
  6. {Series2,Series3} 

也就是要讀取Series2和Serie3中的數(shù)據(jù),而Posting中的Ref(Series2)和Ref(Series3)即為這兩Series在index文件中的偏移。

 

Series以Delta的形式記錄了chunkId以及該chunk包含的時(shí)間范圍。這樣就可以很容易過(guò)濾出我們需要的chunk,然后再按照chunk文件的訪問(wèn),即可找到最終的原始數(shù)據(jù)。

SymbolTable

值得注意的是,為了盡量減少我們文件的大小,對(duì)于Label的Name和Value這些有限的數(shù)據(jù),我們會(huì)按照字母序存在符號(hào)表中。由于是有序的,所以我們可以直接將符號(hào)表認(rèn)為是一個(gè)

[]string切片。然后通過(guò)切片的下標(biāo)去獲取對(duì)應(yīng)的sting??紤]如下符號(hào)表:

 

讀取index文件時(shí)候,會(huì)將SymbolTable全部加載到內(nèi)存中,并組織成symbols []string這樣的切片形式,這樣一個(gè)Series中的所有標(biāo)簽值即可通過(guò)切片下標(biāo)訪問(wèn)得到。

Label Index以及Label Table

事實(shí)上,前面的介紹已經(jīng)將一個(gè)普通數(shù)據(jù)尋址的過(guò)程全部講完了。但是index文件中還包含label索引以及l(fā)abel Table,這兩個(gè)是用來(lái)記錄一個(gè)Label下面所有可能的值而存在的。

這樣,在正則的時(shí)候就可以非常容易的找到我們需要哪些LabelPair。詳情可以見前篇。

 

事實(shí)上,真正的Label Index比圖中要復(fù)雜一點(diǎn)。它設(shè)計(jì)成一條LabelIndex可以表示(多個(gè)標(biāo)簽組合)的所有數(shù)據(jù)。不過(guò)在Prometheus代碼中只會(huì)采用存儲(chǔ)一個(gè)標(biāo)簽對(duì)應(yīng)所有值的形式。

完整的index文件結(jié)構(gòu)

這里直接給出完整的index文件結(jié)構(gòu),摘自Prometheus中index.md文檔。

  1. ┌────────────────────────────┬─────────────────────┐ 
  2. │ magic(0xBAAAD700) <4b>     │ version(1) <1 byte> │ 
  3. ├────────────────────────────┴─────────────────────┤ 
  4. │ ┌──────────────────────────────────────────────┐ │ 
  5. │ │                 Symbol Table                 │ │ 
  6. │ ├──────────────────────────────────────────────┤ │ 
  7. │ │                    Series                    │ │ 
  8. │ ├──────────────────────────────────────────────┤ │ 
  9. │ │                 Label Index 1                │ │ 
  10. │ ├──────────────────────────────────────────────┤ │ 
  11. │ │                      ...                     │ │ 
  12. │ ├──────────────────────────────────────────────┤ │ 
  13. │ │                 Label Index N                │ │ 
  14. │ ├──────────────────────────────────────────────┤ │ 
  15. │ │                   Postings 1                 │ │ 
  16. │ ├──────────────────────────────────────────────┤ │ 
  17. │ │                      ...                     │ │ 
  18. │ ├──────────────────────────────────────────────┤ │ 
  19. │ │                   Postings N                 │ │ 
  20. │ ├──────────────────────────────────────────────┤ │ 
  21. │ │               Label Index Table              │ │ 
  22. │ ├──────────────────────────────────────────────┤ │ 
  23. │ │                 Postings Table               │ │ 
  24. │ ├──────────────────────────────────────────────┤ │ 
  25. │ │                      TOC                     │ │ 
  26. │ └──────────────────────────────────────────────┘ │ 
  27. └──────────────────────────────────────────────────┘ 

tombstones

由于Prometheus Block的數(shù)據(jù)一般在寫完后就不會(huì)變動(dòng)。如果要?jiǎng)h除部分?jǐn)?shù)據(jù),就只能記錄一下刪除數(shù)據(jù)的范圍,由下一次compactor組成新block的時(shí)候刪除。而記錄這些信息的文件即是tomstones。

 

總結(jié)

Prometheus作為時(shí)序數(shù)據(jù)庫(kù),設(shè)計(jì)了各種文件結(jié)構(gòu)來(lái)保存海量的監(jiān)控?cái)?shù)據(jù),同時(shí)還兼顧了性能。只有徹底了解其存儲(chǔ)結(jié)構(gòu),才能更好的指導(dǎo)我們應(yīng)用它!

本文轉(zhuǎn)載自微信公眾號(hào)「解Bug之路」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系解Bug之路公眾號(hào)。  

 

責(zé)任編輯:武曉燕 來(lái)源: 解Bug之路
相關(guān)推薦

2021-02-22 10:37:47

存儲(chǔ)Prometheus

2021-03-15 10:10:29

數(shù)據(jù)庫(kù)數(shù)據(jù)查詢

2021-03-08 10:18:55

數(shù)據(jù)庫(kù)數(shù)據(jù)Prometheus

2017-11-20 11:37:19

時(shí)序數(shù)據(jù)數(shù)據(jù)存儲(chǔ)HBase

2022-07-06 15:41:55

數(shù)據(jù)庫(kù)

2022-09-23 07:44:48

時(shí)序數(shù)據(jù)庫(kù)物聯(lián)網(wǎng)

2021-09-26 10:08:33

TSDB時(shí)序數(shù)據(jù)庫(kù)壓縮解壓

2022-07-11 10:45:12

數(shù)據(jù)庫(kù)分析

2020-03-11 09:50:21

時(shí)序數(shù)據(jù)庫(kù)快速檢索

2022-07-11 11:12:32

數(shù)據(jù)分析

2022-12-18 19:38:31

時(shí)序數(shù)據(jù)庫(kù)數(shù)據(jù)庫(kù)

2018-04-16 08:44:51

InfluxDB TS時(shí)序數(shù)據(jù)庫(kù)存儲(chǔ)

2021-08-31 14:01:59

時(shí)序數(shù)據(jù)庫(kù)數(shù)據(jù)庫(kù)數(shù)據(jù)

2022-07-07 12:23:29

數(shù)據(jù)庫(kù)

2022-06-10 17:37:37

數(shù)據(jù)庫(kù)

2022-07-07 12:37:27

數(shù)據(jù)

2021-08-04 05:49:40

數(shù)據(jù)庫(kù)數(shù)時(shí)序數(shù)據(jù)庫(kù)技術(shù)

2017-09-05 14:45:14

時(shí)序數(shù)據(jù)數(shù)據(jù)庫(kù)大數(shù)據(jù)

2018-06-26 09:37:07

時(shí)序數(shù)據(jù)庫(kù)FacebookNoSQL

2019-05-30 08:31:39

數(shù)據(jù)庫(kù)QTSDB分布式
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)