<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          淺談Prometheus的數(shù)據(jù)存儲(chǔ)

          共 17155字,需瀏覽 35分鐘

           ·

          2021-08-14 06:01

          目錄

          • 1、概述

          • 2、時(shí)間序列

          • 3、二維模型

          • 4、存儲(chǔ)策略的演進(jìn)

            • 4.1 1.x 版本

            • 4.2 2.x 版本



          本文是結(jié)合耗子叔的視頻及 Prometheus 作者部分原文整理,加上部分個(gè)人理解而來(lái),膜拜大神~

          1、概述

          Prometheus是一套開(kāi)源的監(jiān)控&報(bào)警&時(shí)間序列數(shù)據(jù)庫(kù)的組合

          Prometheus內(nèi)部主要分為三大塊,Retrieval是負(fù)責(zé)定時(shí)去暴露的目標(biāo)頁(yè)面上去抓取采樣指標(biāo)數(shù)據(jù),Storage是負(fù)責(zé)將采樣數(shù)據(jù)寫(xiě)磁盤(pán),PromQLPrometheus提供的查詢(xún)語(yǔ)言模塊

          其有著非常高效的時(shí)間序列數(shù)據(jù)存儲(chǔ)方法,每個(gè)采樣數(shù)據(jù)僅僅占用3.5byte左右空間

          在早期有一個(gè)單獨(dú)的項(xiàng)目叫做 TSDB,但是,在2.1.x的某個(gè)版本,已經(jīng)不單獨(dú)維護(hù)這個(gè)項(xiàng)目了,直接將這個(gè)項(xiàng)目合并到了prometheus的主干上了

          prometheus每次抓取的數(shù)據(jù),對(duì)于操作者來(lái)說(shuō)可見(jiàn)的格式(即在prometheus界面查詢(xún)到的值)

          requests_total{path="/status", method="GET", instance="10.0.0.1:80"} @1534317560938 94355

          意思就是在1534317560938這個(gè)時(shí)間點(diǎn),10.0.0.1:80這個(gè)實(shí)例上,GET /status 這個(gè)請(qǐng)求的次數(shù)累計(jì)是 94355

          最終存儲(chǔ)在TSDB中的格式為

          {__name__="requests_total", path="/status", method="GET", instance="10.0.0.1:80"}

          2、時(shí)間序列

          • Data scheme數(shù)據(jù)標(biāo)識(shí)
          identifier -> (t0, v0), (t1, v1), (t2, v2), (t3, v3), ...
          • Prometheus Data Model數(shù)據(jù)模型
          <metric name>{<label name>=<label value>, ...}
          • Typical set of series identifiers

          • Query 查詢(xún)

          __name__="requests_total":查詢(xún)所有屬于requests_total的序列

          method="PUT|POST":查詢(xún)所有序列中方法是PUTPOST的序列

          3、二維模型

          • Write 寫(xiě):每個(gè)目標(biāo)暴露成百上千個(gè)不同的時(shí)間序列,寫(xiě)入模式是完全垂直和高度并發(fā)的,因?yàn)閬?lái)自每個(gè)目標(biāo)的樣本是獨(dú)立的

          • Query 查:查詢(xún)數(shù)據(jù)時(shí)可以并行和批處理

          series
            ^
            │   . . . . . . . . . . . . . . . . .   . . . . .   {__name__="request_total", method="GET"}
            │     . . . . . . . . . . . . . . . . . . . . . .   {__name__="request_total", method="POST"}
            │         . . . . . . .
            │       . . .     . . . . . . . . . . . . . . . .                  ...
            │     . . . . . . . . . . . . . . . . .   . . . .
            │     . . . . . . . . . .   . . . . . . . . . . .   {__name__="errors_total", method="POST"}
            │           . . .   . . . . . . . . .   . . . . .   {__name__="errors_total", method="GET"}
            │         . . . . . . . . .       . . . . .
            │       . . .     . . . . . . . . . . . . . . . .                  ...
            │     . . . . . . . . . . . . . . . .   . . . .
            v
              <-------------------- time --------------------->

          二維模型中橫軸表示時(shí)間,縱軸表示各數(shù)據(jù)點(diǎn)

          這類(lèi)設(shè)計(jì)會(huì)帶來(lái)的問(wèn)題如下

          存儲(chǔ)問(wèn)題

          如上圖所示,在二維模型中的讀寫(xiě)差別是很大的

          (時(shí)間序列查詢(xún))讀時(shí)帶來(lái)的隨機(jī)讀問(wèn)題和查詢(xún)帶來(lái)的隨機(jī)寫(xiě)問(wèn)題,(查詢(xún))讀往往會(huì)比寫(xiě)更復(fù)雜,這是很慢的。盡管用了SSD,但會(huì)帶來(lái)寫(xiě)放大的問(wèn)題,SSD4k寫(xiě),256k刪除,SSD之所以快,實(shí)際上靠的是算法,因此在文件碎片如此大的情況下,都是不能滿足的

          理想狀態(tài)下的寫(xiě)應(yīng)該是順序?qū)?、批量?xiě),對(duì)于相同的時(shí)間序列讀應(yīng)該也是順序讀

          4、存儲(chǔ)策略的演進(jìn)

          4.1 1.x 版本

          1.x 版本下,存儲(chǔ)情況是這樣的

          • 每個(gè)時(shí)間序列都對(duì)應(yīng)一個(gè)文件
          • 在內(nèi)存中批量處理 1kb 的的 chunk
             ┌──────────┬─────────┬─────────┬─────────┬─────────┐           series A
             └──────────┴─────────┴─────────┴─────────┴─────────┘
                    ┌──────────┬─────────┬─────────┬─────────┬─────────┐    series B
                    └──────────┴─────────┴─────────┴─────────┴─────────┘
                                        . . .
           ┌──────────┬─────────┬─────────┬─────────┬─────────┬─────────┐   series XYZ
           └──────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
             chunk 1    chunk 2   chunk 3     ...

          存在的問(wèn)題:

          • chunk保存在內(nèi)存中,如果應(yīng)用程序或節(jié)點(diǎn)崩潰,它可能會(huì)丟失

          • 由于時(shí)間序列的維度很多,對(duì)于的文件個(gè)數(shù)也會(huì)很多,這可能耗盡操作系統(tǒng)的inode

          • 上千的chunk保存在硬盤(pán)需要持久化,可能會(huì)導(dǎo)致磁盤(pán)I/O非常繁忙

          • 磁盤(pán)I/O打開(kāi)很多的文件,會(huì)導(dǎo)致非常高的延遲

          • 舊數(shù)據(jù)需要清理,這可能會(huì)導(dǎo)致SSD的寫(xiě)放大

          • 非常大的CPU、內(nèi)存、磁盤(pán)資源消耗

          • 序列的丟失和變動(dòng)

          例如一些時(shí)間序列變得不活躍,而另一些時(shí)間序列變得活躍,原因在于例如k8s中應(yīng)用程序的連續(xù)自動(dòng)擴(kuò)展和頻繁滾動(dòng)更新帶來(lái)的實(shí)例的ip等變化,每天可能會(huì)創(chuàng)建數(shù)萬(wàn)個(gè)新應(yīng)用程序?qū)嵗约叭碌臅r(shí)間序列集

          因此,即使整個(gè)基礎(chǔ)設(shè)施的規(guī)模大致保持不變,隨著時(shí)間的推移,數(shù)據(jù)庫(kù)中的時(shí)間序列也會(huì)線性增長(zhǎng)。即使Prometheus服務(wù)器能夠收集1000萬(wàn)個(gè)時(shí)間序列的數(shù)據(jù),但如果必須在10億個(gè)序列中找到數(shù)據(jù),查詢(xún)性能會(huì)受到很大影響

          series
            ^
            │   . . . . . .
            │   . . . . . .
            │   . . . . . .
            │               . . . . . . .
            │               . . . . . . .
            │               . . . . . . .
            │                             . . . . . .
            │                             . . . . . .
            │                                         . . . . .
            │                                         . . . . .
            │                                         . . . . .
            v
              <-------------------- time --------------------->

          4.2 2.x 版本

          2.x 時(shí)代的存儲(chǔ)布局

          https://github.com/prometheus/prometheus/blob/release-2.25/tsdb/docs/format/README.md

          4.2.1 數(shù)據(jù)存儲(chǔ)分塊

          • 01xxxxx 數(shù)據(jù)塊

            ULID,和UUID一樣,但是是按照字典和編碼的創(chuàng)建時(shí)間排序的

          • chunk 目錄

            包含各種系列的原始數(shù)據(jù)點(diǎn)塊,但不再是每個(gè)序列對(duì)應(yīng)一個(gè)單一的文件

          • index 數(shù)據(jù)索引

            可以通過(guò)標(biāo)簽找到數(shù)據(jù),這里保存了LabelSeries的數(shù)據(jù)

          • meta.json 可讀元數(shù)據(jù)

            對(duì)應(yīng)存儲(chǔ)和它包含的數(shù)據(jù)的狀態(tài)

          • tombstone

            刪除的數(shù)據(jù)將被記錄到這個(gè)文件中,而不是從塊文件中刪除

          • wal 預(yù)寫(xiě)日志 Write-Ahead Log

            WAL段將被截?cái)嗟?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(150, 84, 181);">checkpoint.X目錄中

          • chunks_head

            在內(nèi)存中的數(shù)據(jù)

          • 數(shù)據(jù)將每 2 小時(shí)保存到磁盤(pán)中

          • WAL 用于數(shù)據(jù)恢復(fù)

          • 2 小時(shí)塊可以高效查詢(xún)范圍數(shù)據(jù)

          分塊存儲(chǔ)后,每個(gè)目錄都是獨(dú)立的存儲(chǔ)目錄,結(jié)構(gòu)如下:

          $ tree ./data
          ./data
          ├── b-000001
          │   ├── chunks
          │   │   ├── 000001
          │   │   ├── 000002
          │   │   └── 000003
          │   ├── index
          │   └── meta.json
          ├── b-000004
          │   ├── chunks
          │   │   └── 000001
          │   ├── index
          │   └── meta.json
          ├── b-000005
          │   ├── chunks
          │   │   └── 000001
          │   ├── index
          │   └── meta.json
          └── b-000006
              ├── meta.json
              └── wal
                  ├── 000001
                  ├── 000002
                  └── 000003

          分塊存儲(chǔ)對(duì)應(yīng)著Blocks,可以看做是小型數(shù)據(jù)庫(kù)

          • 將數(shù)據(jù)分成互不重疊的塊

            每個(gè)塊都充當(dāng)一個(gè)完全獨(dú)立的數(shù)據(jù)庫(kù)

            包含其時(shí)間窗口的所有時(shí)間序列數(shù)據(jù)

            有自己的索引和塊文件集

          • 每個(gè)數(shù)據(jù)塊都是不可變的

          • 當(dāng)前塊可以追加數(shù)據(jù)

          • 所有新數(shù)據(jù)都寫(xiě)入內(nèi)存數(shù)據(jù)庫(kù)

          • 為了防止數(shù)據(jù)丟失,還寫(xiě)了一個(gè)臨時(shí) WAL

          t0            t1             t2             t3             now
           ┌───────────┐  ┌───────────┐  ┌───────────┐  ┌───────────┐
           │           │  │           │  │           │  │           │                 ┌────────────┐
           │           │  │           │  │           │  │  mutable  │ <─── write ──── ┤ Prometheus │
           │           │  │           │  │           │  │           │                 └────────────┘
           └───────────┘  └───────────┘  └───────────┘  └───────────┘                        ^
                 └──────────────┴───────┬──────┴──────────────┘                              │
                                        │                                                  query
                                        │                                                    │
                                      merge ─────────────────────────────────────────────────┘

          4.2.2 block 合并

          上面分離了block后,會(huì)帶來(lái)的問(wèn)題

          • 當(dāng)查詢(xún)多個(gè)塊時(shí),必須將它們的結(jié)果合并到一個(gè)整體結(jié)果中
          • 如果我們需要一個(gè)星期的查詢(xún),它必須合并 80 多個(gè) block 塊
          t0             t1            t2             t3             t4             now
           ┌────────────┐  ┌──────────┐  ┌───────────┐  ┌───────────┐  ┌───────────┐
           │ 1          │  │ 2        │  │ 3         │  │ 4         │  │ 5 mutable │    before
           └────────────┘  └──────────┘  └───────────┘  └───────────┘  └───────────┘
           ┌─────────────────────────────────────────┐  ┌───────────┐  ┌───────────┐
           │ 1              compacted                │  │ 4         │  │ 5 mutable │    after (option A)
           └─────────────────────────────────────────┘  └───────────┘  └───────────┘
           ┌──────────────────────────┐  ┌──────────────────────────┐  ┌───────────┐
           │ 1       compacted        │  │ 3      compacted         │  │ 5 mutable │    after (option B)
           └──────────────────────────┘  └──────────────────────────┘  └───────────┘

          4.2.3 數(shù)據(jù)保留

                                |
           ┌────────────┐  ┌────┼─────┐  ┌───────────┐  ┌───────────┐  ┌───────────┐
           │ 1          │  │ 2  |     │  │ 3         │  │ 4         │  │ 5         │   . . .
           └────────────┘  └────┼─────┘  └───────────┘  └───────────┘  └───────────┘
                                |
                                |
                       retention boundary

          1塊可以被安全刪除,第2塊必須保持直到它完全超出邊界

          塊合并帶來(lái)的影響

          • 塊壓縮可能使塊太大而無(wú)法刪除
          • 需要限制塊的大小
          最大塊大小 = 保留窗口 * 10%

          4.2.4 查詢(xún)和索引

          主要特點(diǎn)

          • 使用倒排索引,倒排索引提供基于其內(nèi)容子集的數(shù)據(jù)項(xiàng)的快速查找。例如,可以查找所有具有標(biāo)簽的系列,app=”nginx"而無(wú)需遍歷每個(gè)系列并檢查它是否包含該標(biāo)簽

          • 正向索引,為每個(gè)序列分配一個(gè)唯一的ID,通過(guò)它可以在恒定的時(shí)間內(nèi)檢索

          一個(gè)目錄中保存了很多Series,如果想要根據(jù)一個(gè)Label來(lái)查詢(xún)對(duì)應(yīng)的所有Series,具體流程是什么呢

          為每個(gè)Series中的所有Label都建立了一個(gè)倒排索引

          LabelSeries
          __name__="requests_total"{__name__="requests_total", path="/status", method="GET", instance=”10.0.0.1:80”}
          path="/status"{__name__="requests_total", path="/status", method="GET", instance=”10.0.0.1:80”}
          method="GET"{__name__="requests_total", path="/status", method="GET", instance=”10.0.0.1:80”}
          instance=”10.0.0.1:80”{__name__="requests_total", path="/status", method="GET", instance=”10.0.0.1:80”}

          正向索引的引入,給每個(gè)Series分配了一個(gè)ID,便于組合查詢(xún)

          LabelSeriesID
          __name__="requests_total"1001
          path="/status"1001
          method="GET"1001
          instance=”10.0.0.1:80”1001

          例如,如果查詢(xún)的語(yǔ)句是:__name __ =“requests_total” AND app =“nginx”

          需要先分別找出對(duì)應(yīng)的倒排索引,再求交集,由此會(huì)帶來(lái)一定的時(shí)間復(fù)雜度O(N2,為了減少時(shí)間復(fù)雜度,實(shí)際上倒排索引中的SeriesID是有序的,那么采取ZigZag的查找方式,可以保證在O(N)的時(shí)間復(fù)雜來(lái)找到最終的結(jié)果

          4.2.6 WAL

          通過(guò)mmap(不經(jīng)過(guò)文件系統(tǒng)的寫(xiě)數(shù)據(jù)方式),同時(shí)在內(nèi)存和WAL預(yù)寫(xiě)日志Write-Ahead Log中保存數(shù)據(jù),即可以保證數(shù)據(jù)的持久不丟失,又可以保證崩潰之后從故障中恢復(fù)的時(shí)間很短,因?yàn)槭菑膬?nèi)存中恢復(fù)

          4.2.7 小結(jié)

          新的存儲(chǔ)結(jié)構(gòu)帶來(lái)的好處

          • 在查詢(xún)某個(gè)時(shí)間范圍時(shí),可以輕松忽略該范圍之外的所有數(shù)據(jù)塊。它通過(guò)減少檢查數(shù)據(jù)集來(lái)輕松解決數(shù)據(jù)流失問(wèn)題
          • 當(dāng)完成一個(gè)塊時(shí),可以通過(guò)順序?qū)懭胍恍┹^大的文件來(lái)保存內(nèi)存數(shù)據(jù)庫(kù)中的數(shù)據(jù)。避免任何寫(xiě)放大,并同樣為 SSDHDD提供服務(wù)
          • 保留了V2的良好特性,即最近查詢(xún)最多的塊總是在內(nèi)存中的
          • 不再受限于固定的1KiB塊大小來(lái)更好地對(duì)齊磁盤(pán)上的數(shù)據(jù)。可以選擇對(duì)單個(gè)數(shù)據(jù)點(diǎn)和所選壓縮格式最有意義的任何大小
          • 刪除舊數(shù)據(jù)變得非常便宜和即時(shí),只需要?jiǎng)h除一個(gè)目錄。在舊版本的存儲(chǔ)中,必須分析和重寫(xiě)多達(dá)數(shù)億個(gè)文件,這可能需要數(shù)小時(shí)才能收斂

          參考資料

          [1]

          https://www.bilibili.com/video/BV1a64y1X7ys

          [2]

          https://fabxc.org/tsdb/

          [3]

          http://ganeshvernekar.com/blog/prometheus-tsdb-the-head-block/

          瀏覽 67
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产爽爽操逼91 | 国产高清一级 | 手机在线操B视频 | 激情五月婷婷 | 在线观看欧美一区二区 |