<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Prometheus時序數據庫-磁盤中的存儲結構

      Prometheus時序數據庫-磁盤中的存儲結構

      前言

      之前的文章里,筆者詳細描述了監控數據在Prometheus內存中的結構。而其在磁盤中的存儲結構,也是非常有意思的,關于這部分內容,將在本篇文章進行闡述。

      磁盤目錄結構

      首先我們來看Prometheus運行后,所形成的文件目錄結構

      在筆者自己的機器上的具體結構如下:

      prometheus-data
      	|-01EY0EH5JA3ABCB0PXHAPP999D (block)
      	|-01EY0EH5JA3QCQB0PXHAPP999D (block)
      		|-chunks
      			|-000001
      			|-000002
      			.....
      			|-000021
      		|-index
      		|-meta.json
      		|-tombstones
      	|-wal
      	|-chunks_head
      

      Block

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

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

      meta.json

      我們可以通過檢查meta.json來得到當前Block的一些元信息。

      {
      	"ulid":"01EY0EH5JA3QCQB0PXHAPP999D"
      	// maxTime-minTime = 7200s => 2 h
      	"minTime": 1611664000000
      	"maxTime": 1611671200000
      	"stats": {
      		"numSamples": 1505855631,
      		"numSeries": 12063563,
      		"numChunks": 12063563
      	}
      	"compaction":{
      		"level" : 1
      		"sources: [
      			"01EY0EH5JA3QCQB0PXHAPP999D"
      		]
      	}
      	"version":1
      }
      

      其中的元信息非常清楚明了。這個Block記錄了從2個小時的數據。

      讓我們再找一個比較陳舊的Block看下它的meta.json.

      	"ulid":"01EXTEH5JA3QCQB0PXHAPP999D",
      	// maxTime - maxTime =>162h
      	"minTime":1610964800000,
      	"maxTime":1611548000000
      	......
      	"compaction":{
      		"level": 5,
      		"sources: [
      			31個01EX......
      		]
      	},
      	"parents: [
      		{	
      			"ulid": 01EXTEH5JA3QCQB1PXHAPP999D
      			...
      		}
      		{	
      			"ulid": 01EXTEH6JA3QCQB1PXHAPP999D
      			...
      		}
      				{	
      			"ulid": 01EXTEH5JA31CQB1PXHAPP999D
      			...
      		}
      	]
      

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

      Chunks結構

      CUT文件切分

      所有的Chunk文件在磁盤上都不會大于512M,對應的源碼為:

      func (w *Writer) WriteChunks(chks ...Meta) error {
      	......
      	for i, chk := range chks {
      		cutNewBatch := (i != 0) && (batchSize+SegmentHeaderSize > w.segmentSize)
      		......
      		if cutNewBatch {
      			......
      		}
      		......
      	}
      }
      

      當寫入磁盤單個文件超過512M的時候,就會自動切分一個新的文件。

      一個Chunks文件包含了非常多的內存Chunk結構,如下圖所示:

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

      chunks文件通過mmap去訪問

      由于chunks文件大小基本固定(最大512M),所以我們很容易的可以通過mmap去訪問對應的數據。直接將對應文件的讀操作交給操作系統,既省心又省力。對應代碼為:

      func NewDirReader(dir string, pool chunkenc.Pool) (*Reader, error) {
      	......
      	for _, fn := range files {
      		f, err := fileutil.OpenMmapFile(fn)
      		......
      	}
      	......
      	bs = append(bs, realByteSlice(f.Bytes()))
      }
      通過sgmBytes := s.bs[offset]就直接能獲取對應的數據
      

      index索引結構

      前面介紹完chunk文件,我們就可以開始闡述最復雜的索引結構了。

      尋址過程

      索引就是為了讓我們快速的找到想要的內容,為了便于理解。筆者就通過一次數據的尋址來探究Prometheus的磁盤索引結構。考慮查詢一個

      擁有系列三個標簽
      ({__name__:http_requests}{job:api-server}{instance:0})
      且時間為start/end的所有序列數據
      

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

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

      TOC(Table Of Content)


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

      func NewTOCFromByteSlice(bs ByteSlice) (*TOC, error) {
      	......
      	// indexTOCLen = 6*8+4 = 52
      	b := bs.Range(bs.Len()-indexTOCLen, bs.Len())
      	......
      	return &TOC{
      		Symbols:           d.Be64(),
      		Series:            d.Be64(),
      		LabelIndices:      d.Be64(),
      		LabelIndicesTable: d.Be64(),
      		Postings:          d.Be64(),
      		PostingsTable:     d.Be64(),
      	}, nil
      }
      

      Posting offset table 以及 Posting倒排索引

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

      Series

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

      {series1,Series2,Series3,Series4}
      ∩
      {series1,Series2,Series3}
      ∩
      {Series2,Series3}
      =
      {Series2,Series3}
      

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

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

      SymbolTable

      值得注意的是,為了盡量減少我們文件的大小,對于Label的Name和Value這些有限的數據,我們會按照字母序存在符號表中。由于是有序的,所以我們可以直接將符號表認為是一個
      []string切片。然后通過切片的下標去獲取對應的sting。考慮如下符號表:

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

      Label Index以及Label Table

      事實上,前面的介紹已經將一個普通數據尋址的過程全部講完了。但是index文件中還包含label索引以及label Table,這兩個是用來記錄一個Label下面所有可能的值而存在的。
      這樣,在正則的時候就可以非常容易的找到我們需要哪些LabelPair。詳情可以見前篇。

      事實上,真正的Label Index比圖中要復雜一點。它設計成一條LabelIndex可以表示(多個標簽組合)的所有數據。不過在Prometheus代碼中只會采用存儲一個標簽對應所有值的形式。

      完整的index文件結構

      這里直接給出完整的index文件結構,摘自Prometheus中index.md文檔。

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

      tombstones

      由于Prometheus Block的數據一般在寫完后就不會變動。如果要刪除部分數據,就只能記錄一下刪除數據的范圍,由下一次compactor組成新block的時候刪除。而記錄這些信息的文件即是tomstones。

      總結

      Prometheus作為時序數據庫,設計了各種文件結構來保存海量的監控數據,同時還兼顧了性能。只有徹底了解其存儲結構,才能更好的指導我們應用它!

      歡迎大家關注我公眾號,里面有各種干貨,還有大禮包相送哦!

      posted @ 2021-03-01 09:59  無毀的湖光-Al  閱讀(1474)  評論(3)    收藏  舉報
      主站蜘蛛池模板: 免费看成人欧美片爱潮app| 色就色中文字幕在线视频| 国内精品久久人妻无码不卡| 国产最新精品系列第三页| 亚洲精品日韩在线观看| 国产人妻精品午夜福利免费 | 久久精品午夜视频| 99精品久久久中文字幕| 国产精品三级爽片免费看| 天堂mv在线mv免费mv香蕉| 亚洲精中文字幕二区三区| 日本强好片久久久久久aaa| 午夜福利偷拍国语对白| 噜噜综合亚洲av中文无码| 黑山县| 成人无码一区二区三区网站| 在线免费观看视频1区| 欧美人妻在线一区二区| 色悠悠成人综合在线视频| 国产一区二区三区色噜噜| 国产精品疯狂输出jk草莓视频| 日本高清视频网站www| 亚洲日韩乱码中文无码蜜桃臀| 手机看片福利一区二区三区| 亚洲午夜性猛春交XXXX| 国产精品理论片| 欧美人人妻人人澡人人尤物| 成人免费无遮挡在线播放| 国产欧美综合在线观看第十页| www亚洲精品| 成在线人午夜剧场免费无码| 污网站在线观看视频| 国产suv精品一区二区五| 亚洲AV无码专区亚洲AV紧身裤 | 99在线视频免费观看| 在线 国产 欧美 专区| 无码日韩精品一区二区三区免费 | 亚洲精品天堂一区二区| 久热综合在线亚洲精品| 精品日本乱一区二区三区| 国产精品久久久尹人香蕉|