自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

[[384167]]

前言

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

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

首先我們來看Prometheus運行后,所形成的文件目錄結(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

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

 

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

meta.json

我們可以通過檢查meta.json來得到當(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 

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

 

讓我們再找一個比較陳舊的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個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個原始Block經(jīng)歷5次壓縮而來。最后一次壓縮的三個Block ulid記錄在parents中。如下圖所示:

 

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

CUT文件切分

所有的Chunk文件在磁盤上都不會大于512M,對應(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)寫入磁盤單個文件超過512M的時候,就會自動切分一個新的文件。

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

 

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

chunks文件通過mmap去訪問

由于chunks文件大小基本固定(最大512M),所以我們很容易的可以通過mmap去訪問對應(yīng)的數(shù)據(jù)。直接將對應(yīng)文件的讀操作交給操作系統(tǒng),既省心又省力。對應(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. 通過sgmBytes := s.bs[offset]就直接能獲取對應(yīng)的數(shù)據(jù) 

 

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

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

尋址過程

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

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

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

 

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

TOC(Table Of Content)

 

由于index文件一旦形成之后就不再會改變,所以Prometheus也依舊使用mmap來進(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倒排索引

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

 

Series

我們通過三條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包含的時間范圍。這樣就可以很容易過濾出我們需要的chunk,然后再按照chunk文件的訪問,即可找到最終的原始數(shù)據(jù)。

SymbolTable

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

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

 

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

Label Index以及Label Table

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

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

 

事實上,真正的Label Index比圖中要復(fù)雜一點。它設(shè)計成一條LabelIndex可以表示(多個標(biāo)簽組合)的所有數(shù)據(jù)。不過在Prometheus代碼中只會采用存儲一個標(biāo)簽對應(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ù)一般在寫完后就不會變動。如果要刪除部分?jǐn)?shù)據(jù),就只能記錄一下刪除數(shù)據(jù)的范圍,由下一次compactor組成新block的時候刪除。而記錄這些信息的文件即是tomstones。

 

總結(jié)

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

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

 

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

2021-02-22 10:37:47

存儲Prometheus

2021-03-08 10:18:55

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

2021-03-15 10:10:29

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

2017-11-20 11:37:19

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

2022-07-06 15:41:55

數(shù)據(jù)庫

2022-09-23 07:44:48

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

2021-09-26 10:08:33

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

2020-03-11 09:50:21

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

2022-07-11 10:45:12

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

2022-07-11 11:12:32

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

2022-12-18 19:38:31

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

2018-04-16 08:44:51

InfluxDB TS時序數(shù)據(jù)庫存儲

2021-08-31 14:01:59

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

2022-07-07 12:23:29

數(shù)據(jù)庫

2022-06-10 17:37:37

數(shù)據(jù)庫

2022-07-07 12:37:27

數(shù)據(jù)

2018-06-26 09:37:07

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

2021-08-04 05:49:40

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

2017-09-05 14:45:14

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

2019-05-30 08:31:39

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

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