OpentTsdb官方文檔中文版----上卷和預聚合

  雖然TSDB被設計爲只要有空間就可以存儲原始全分辨率(resolution)的數據,但是對於廣泛的時間範圍或在許多標籤組合之上的查詢可能是相當痛苦的。這樣的查詢可能需要很長時間才能完成,或者在最糟糕的情況下,可能會導致內存不足的異常。從OpenTSDB 2.4開始,一組新的API允許存儲和查詢較低分辨率的數據以更快地回答這樣的查詢。本頁將概述上卷和預聚合是什麼,它們如何在TSDB中工作以及如何最好地使用它們。查看API部分的具體實現細節。

注意:
  OpenTSDB本身不計算和存儲上卷或預聚合數據。有多種計算結果的方法,但是根據規模和精度要求,它們都有好處和缺點。請參閱生成上卷和預聚合部分,討論如何創建此數據。

示例數據

  爲了幫助描述較低分辨率的數據,我們來看一些完整的分辨率(也稱爲原始數據)的示例數據。第一個表格用快捷標識符定義時間序列。

序列ID Metric Tag1 Tag2 Tag3
ts1 system.if.bytes.out host=web01 colo=lga interface=eth0
ts2 system.if.bytes.out host=web02 colo=lga interface=eth0
ts3 system.if.bytes.out host=web03 colo=sjc interface=eth0
ts4 system.if.bytes.out host=web04 colo=sjc interface=eth0

請注意,它們都具有相同metric和interface標記,但不同host和colo標籤。

接下來以15分鐘的時間間隔寫出一些數據:

序列ID 12:00 12:15 12:30 12:45 13:00 13:15 13:30 13: 45
ts1 1 4 -3 8 2 -4 5 2
ts2 7 2 8 -9 4 1 1
ts3 9 3 -2 -1 6 3 8 2
ts4 2 5 2 8 5 -4 7

請注意,有些數據點丟失。有了這些數據集,我們先看看上卷。

上卷

  在OpenTSDB中,“上卷”被定義爲隨着時間的推移聚合彙總的單個時間序列。它也可以被稱爲“基於時間的聚合”。上卷幫助解決在廣泛的時間跨度的問題。例如,如果每60秒寫入一個數據點並查詢一年的數據,則時間序列將返回超過525,000個單獨的數據點。圖表會有很多點並且很可能會相當凌亂。相反,可能需要查看較低分辨率的數據,例如,只需要8k左右1小時數據進行繪圖。然後,可以識別異常並向下鑽取更精細的分辨率數據。
  如果您已經使用OpenTSDB查詢數據,則您可能熟悉將每個時間序列聚合爲更小或更低分辨率值的降採樣器。上卷實質上是系統中存儲的降採樣的結果,並隨意調用。每個上卷(或降採樣器)需要兩條信息:

  • 間隔(Interval): 多少時間“滾動”到新的值。例如,一個小時(1h)的數據或一天(1d)的數據。
  • 聚合函數:對基礎值進行了什麼算術運算才能得到新值。例如sum:累加所有的值或max:存儲最大值。

警告
  存儲上卷時,最好避免平均值,中值或偏差等函數(average, median or deviation)。在進一步降採樣或分組聚合時,這些值變得毫無意義。相反,總是存儲總和(sum)和計數(count)要好得多,至少可以在查詢時計算平均值。有關更多信息,請參閱下面的部分。

  上卷數據點的時間戳應該捕捉到(snap to)上卷間隔的頂部。例如,如果彙總間隔是1h那麼它包含1小時的數據,並應該快速(snap to)到小時的頂部。(因爲所有的時間戳都是用Unix Epoch格式編寫的,定義爲UTC時區,所以這將是一個小時UTC時間的開始)。

上卷示例

對於前述給定的數據,使用1h的間隔存儲sum和count。

序列ID 12:00 13:00
ts1 SUM 10 5
ts1 COUNT 4 4
ts2 SUM 8 6
ts2 COUNT 4 3
ts3 SUM 9 19
ts3 COUNT 4 4
ts4 SUM 9 16
ts4 COUNT 3 4

  請注意,無論間隔“bucket”中的第一個數據點何時出現,所有時間戳都對齊到小時的頂部。另請注意,如果一個數據點在一段時間內不存在,則計數較低。
  在一般情況下,在每個時間序列存儲上卷時,目標應該是計算和存儲MAX,MIN,SUM和COUNT。

平均上卷示例

  當啓用上卷並且請求使用OpenTSDB 的avg函數的降採樣器時,TSD將掃描存儲中SUM和COUNT值。然後在迭代數據的時候,它會精確地計算平均值。
  COUNT和SUM值的時間戳必須匹配。但是,如果一個SUM的預期計數COUNT值缺失,則SUM將會被踢出結果。從上面的例子中,現在我們丟失了一個計數數據點ts2。

序列ID 12:00 13:00
ts1 SUM 10 5
ts1 COUNT 4 4
ts2 SUM 8 6
ts2 COUNT 4

所得到的一個2h降採樣的avg查詢應該是這樣的:

序列ID 12:00
ts1 AVG 1.875
ts2 AVG 2
ts1: (10+5)/8=1.875
ts2: 8/4=2

預聚合

  雖然上卷可以幫助處理較長時間的查詢,但是如果度量具有較高的基數(即給定度量的唯一時間序列數量),仍然可能遇到小範圍查詢性能問題。在上面的例子中,我們有4臺Web服務器。即使我們有10,000臺服務器。獲取網絡流量(interface traffic)的總和或平均值可能會相當慢。如果用戶經常拉取大量分組集合(或一些將它作爲空間集合)的話,存儲聚合和查詢替代很有意義,這樣會獲取更少的數據。
  與上卷不同,預聚合只需要一條額外的信息:

  • 聚合函數:對基礎值進行了什麼算術運算才能得到新值。例如sum:累加所有的值或max:存儲最大值。

  在OpenTSDB中,預聚合與其他帶有特殊標籤的時間序列不同。默認標籤key是_aggregate(可通過tsd.rollups.agg_tag_key配置)。然後用於生成數據的聚合函數以大寫形式存儲在標籤值中。讓我們看一個例子:

預聚合示例

  考慮到頂部的示例,我們可能想要查看colo(數據中心)的總網絡流量。在這種情況下,我們可以通過SUM和COUNT聚合,類似於上卷。結果將是四個伴隨元數據的新的時間序列,如:

序列ID Metric Tag1 Tag2
ts1’ system.if.bytes.out colo=lga _aggregate=SUM
ts2’ system.if.bytes.out colo=lga _aggregate=COUNT
ts3’ system.if.bytes.out colo=sjc _aggregate=SUM
ts4’ system.if.bytes.out colo=sjc _aggregate=COUNT

  請注意,這些時間序列已經丟棄了host和interface標籤。這是因爲,聚合過程中,取了host和interface的多個不同的值,已經包裝到這個新的序列,如果再讓他們作爲標籤,不會再有意義。另外請注意,我們在存儲的數據中注入了新的標籤_aggregate。現在查詢可以通過指定一個_aggregate值來訪問這些數據。

注意:
  啓用了上卷後,如果您計劃使用預聚合,則可能需要通過讓TSDB自動注入_aggregate=RAW來幫助區分預聚合中的原始數據。只需將tsd.rollups.tag_raw屬性設置爲true。

  現在結果數據如下:

序列ID 12:00 12:15 12:30 12:45 13:00 13:15 13:30 13:45
ts1’ 8 6 5 -1 6 -4 6 3
ts2’ 2 2 2 2 2 1 2 2
ts3’ 9 5 3 1 14 8 4 9
ts4’ 1 2 2 2 2 2 2 2

  由於我們正在通過聚合(通過colo分組)來執行分組,所以我們爲每個時間戳從原始數據集中獲取一個值。在這種情況下,我們不採用降採樣或者上卷。

聚合算法:
  根據colo分組,因此ts1與ts2一組,ts3與ts4一組。

ts1’ => SUM:   1+7=8  4+2=6  …
ts2’ => COUNT:  2      2     …
ts3’ => SUM:    9     3+2=5  …
ts4’ => COUNT:  1      2     …         

警告
  和上卷一樣,在編寫預聚合時,最好避免平均值,中值或偏差等函數。只是存儲總和和計數。

上卷 預聚合

  雖然預聚合肯定有助於高基數的指標,但用戶可能仍然希望查詢訪問廣泛的時間跨度,但遇到緩慢的查詢。謝天謝地,可以像原始數據一樣進行上卷預聚合。只要生成預聚合,然後使用上面的信息將其上捲起來。

生成上卷和預聚合

  目前,TSD不會爲您生成上卷數據或預聚合數據。主要原因是意味着OpenTSDB處理大量的時間序列數據,所以單個TSD專注於儘可能快地將數據存儲到存儲中。

問題

  由於TSD的(基本上)無狀態特性,它們可能不具備用於執行預聚合的全套數據。例如,我們的樣本ts1數據可能在寫入TSD_A的同時ts2被寫入TSD_B。不從存儲中讀取數據,也不能執行正確的分組。我們也不知道我們應該在什麼時候進行預聚合。我們可以等待1分鐘,然後預先聚合數據,但會錯過那一分鐘後發生的任何事情。或者我們可以等待一個小時,預先聚合的查詢將不會有最後一個小時的數據。如果數據來得太晚,會發生什麼?
  此外,對於上卷,根據用戶向TSD寫入數據的方式,對於ts1來說,我們可能會收到TSD_A上12:15的數據點,但是數據在12:30到達了TSD_B,因此整個小時都不需要數據(neither has the data required for the full hour)。時間窗口限制也適用於上卷。

解決方案

  使用上卷和預聚合需要一些分析和各種權衡之間的選擇。由於一些OpenTSDB用戶已經具備了計算這類數據的方式和手段,我們只需提供API來存儲和查詢。但是,這裏有一些關於如何自己計算這些的提示。

批處理

  其他時間序列數據庫常用的一種方法是在延遲一段時間後從數據庫中讀取數據,計算出預聚合和上卷,然後寫入數據。這是解決這個問題的最簡單的方法,在小規模下運作良好。但是仍然有一些問題:

  • 隨着數據的增長,生成上卷的查詢也會增長,以至於查詢負載影響寫入和用戶查詢性能。在HBase下啓用數據Compaction時,OpenTSDB會遇到同樣的問題。
  • 同樣隨着數據的增長,更多的數據意味着批處理需要更長的時間,並且必須跨多個Worker共享,這可能是一個協調和排除故障的難題。
  • 延遲或歷史數據可能不會上卷,除非有一些跟蹤手段以觸發舊數據生成新批次。

改進批處理的一些方法包括:

  • 從副本系統中讀取數據,例如,如果設置了HBase副本,則可以讓用戶從Master系統查詢從副本存儲讀取來聚合。
  • 從其他關聯存儲讀取。一個例子是將所有數據鏡像到另一個存儲(如HDFS),並針對該數據運行批處理作業。

在TSD上排隊

  某些數據庫使用的另一個選項是將所有數據排列在進程中的內存中,並在經過配置的時間窗口後寫入結果。但是由於TSD是無狀態的,通常用戶在其TSD之前放置一個負載均衡器,所以單個TSD可能無法得到整個上卷或預聚合的所有數據進行計算(如上所述)。爲了使這種方法起作用,上游收集器必須將計算所需的所有數據發送到特定的TSD。這不是一個困難的任務,但面臨的問題包括:

  • 有足夠的RAM或磁盤空間來爲每個TSD本地化存儲(spool吐)數據。
  • 如果一個TSD進程死亡,您將要麼丟失聚合的數據,要麼必須從存儲引導(bootstrapped)。
  • 每當聚合計算髮生時,原始數據的整體寫入吞吐量就會受到影響。
  • 仍然有延遲/歷史數據問題。
  • 由於TSDB是基於JVM的,將所有這些數據保存在RAM中,然後運行GC將會受到很多影響。(假脫機(spooling)到磁盤更好,但是你會遇到IO問題)

  一般來說,在Writer上排隊是一個壞主意。避免痛苦。

流式處理

  處理上卷和預聚合的一種更好的方法是將數據發送到流處理系統,在那裏它可以被近乎實時地處理並寫入到TSD中。它類似於TSD上的排隊選項,但使用無數的流處理框架之一(Storm,Flink,Spark等)來處理消息路由和內存中的存儲。然後,您只需編寫一些代碼來計算聚合,並在窗口過去後將數據吐出。
  這是許多下一代監控解決方案所使用的解決方案,例如雅虎!雅虎正在努力爲需要大規模監控的其他人開放流處理系統,並將其整齊地插入到TSDB中。

雖然流處理更好,但您仍然遇到以下問題:

  • 足夠的資源讓stream workers去完成他們的作業。
  • 死掉的stream worker需要從存儲引導。
  • 延遲/歷史數據必須處理。

共享

  如果您有計算聚合的工作代碼,請與OpenTSDB組共享。如果您的解決方案是開源的,我們可能會將其納入OpenTSDB生態系統。

配置

  對於Opentsdb 2.4,上卷配置由opentsdb.conf中的Key tsd.rollups.config引用。此鍵的值必須是引號轉義的JSON字符串,不帶換行符,或者最好是包含配置的JSON文件的路徑。文件名必須如rollup_config.json一樣以.json 結尾。
JSON配置應該如下所示:

{
      "aggregationIds": {
              "sum": 0,
              "count": 1,
              "min": 2,
              "max": 3
      },
      "intervals": [{
              "table": "tsdb",
              "preAggregationTable": "tsdb-preagg",
              "interval": "1m",
              "rowSpan": "1h",
              "defaultInterval": true
      }, {
              "table": "tsdb-rollup-1h",
              "preAggregationTable": "tsdb-rollup-preagg-1h",
              "interval": "1h",
              "rowSpan": "1d"
      }]
}

兩個頂級的字段包括:
aggregationIds: 將OpenTSDB聚合函數名稱映射到用於壓縮存儲的數字標識符的映射。
intervals: 包含表名和間隔定義的一個或多個間隔定義的列表。

aggregationIds

  aggregation ids映射用於通過將每種類型的上卷數據預先加上數字ID來減少存儲量,而不是拼出完整的彙總函數。例如,如果我們COUNT:爲每個值的每個列(或壓縮列)添加6個字節,我們可以使用一個ID保存。
  ID必須是從0到127的整數。這意味着我們可以在每個間隔中存儲多達128個不同的上卷。在map中只能爲每個數值提供一個ID,並且只能爲每個類型給定一個聚合函數。如果函數名稱沒有映射到OpenTSDB支持的聚合函數,則會在啓動時引發異常。同樣,至少要給定一個聚合,才能啓動TSD。

警告
  一旦開始寫入數據,聚合ID將無法更改。如果更改映射,則可能會返回不正確的數據,或者查詢和寫入操作可能會失敗。您可以隨時添加函數,但不能改變映射。

intervals

  每個間隔對象都定義了表格路由,以便上卷和預先聚合的數據寫入並查詢。有兩種類型的間隔:

  • 默認 - 這是默認的,原始數據,OpenTSDB表通過"defaultInterval":true定義。對於現有的安裝部署,是tsdb表或tsd.storage.hbase.data_table定義的任意表。忽略間隔和跨度,默認爲OpenTSDB 1小時行寬,並存儲給定分辨率和時間戳的數據。每個TSD和配置一次只能配置一個默認值。
  • 上卷間隔 - 任何設置爲"defaultInterval":false或未設置默認間隔。這些是上卷表,其中值被捕捉到間隔邊界

  應該定義下列字段:

名稱 數據類型 Required 描述 示例
table String Required 非預先彙總的數據的基礎或上卷表。對於默認表,應該是tsdb或現有的原始數據被寫入的表。對於上卷的數據,它必須與原始數據不同表。 tsdb-rollup-1h
preAggregationTable String Required 應該寫入預先聚合的數據和(可選)上卷數據的表。它可能與table值相同,爲同一張表。 tsdb-rollup-preagg-1h
interval String Required 格式爲“<interval><units>”中數據點之間的預期間隔。例如,如果每小時計算一次上卷,則間隔應爲1h。如果每10分鐘計算一次,則將其設置爲10m。對於默認表,該值將被忽略。 1h
rowSpan String Required 存儲中每行的寬度。此值必須大於interval和interval中定義的數字。 例如,如果interval是1h,rowSpan是1天,則每行會有24個值。 1d
defaultInterval Boolean Optional 是否將配置的時間間隔作爲原始未滾動數據的默認值。 true

  在存儲中,上卷的編寫類似於原始數據,每行都有一個基準時間戳,每個數據點是相對於基準時間的偏移量。每個偏移量都是基準時間以外的增量,而不是實際的偏移量。例如,如果一行存儲1天of 1小時的數據,則會有多達24個偏移量。偏移0將映射到午夜的行,偏移量5將映射到上午6點。因爲上卷偏移量是以14位編碼的,所以如果一行中存儲的間隔太多以便適應14位,TSD啓動時會引發錯誤。

警告
  將數據寫入TSD之後,不要更改上卷間隔的間隔寬度或行跨度。這將導致垃圾數據和可能失敗的查詢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章