【萬字乾貨】OpenMetric與時序資料庫儲存模型分析

語言: CN / TW / HK
摘要:解讀OpenMetric規範和指標的模型定義基礎上,結合當下主流的時序資料庫核心儲存及處理技術,嘗試讓使用者(架構師、開發者或使用者)結合自身業務場景選擇合適的產品,消除技術選型的困惑。

本文分享自華為雲社群《【萬字乾貨】OpenMetric與時序資料庫儲存模型分析》,作者: 敏捷的小智。

摘要

近些年時序資料庫發展突飛猛進,IT系統的監控指標就是一種典型的時序資料。由於雲端計算、容器、微服務和Serverless的普遍採用和業務系統的大型化、複雜化;加之IoT的蓬勃發展,海量時序資料的採集、儲存、處理與分析,面臨著全新的需求與挑戰。在解讀OpenMetric規範和指標的模型定義基礎上,結合當下主流的時序資料庫核心儲存及處理技術,嘗試讓使用者(架構師、開發者或使用者)結合自身業務場景選擇合適的產品,消除技術選型的困惑。結合雲服務商的最新動態,為使用者提供開箱即用的、高可靠的多種可選方案,加速應用構建及可運維能力的完善,聚焦核心業務,促進業務成功。

背景

參考DB-ENGINES網站[1]關於各大資料庫排名,是資料庫產品選型的一個重要參考指標。尤其是針對不同業務場景和訴求,在垂直細分領域中關注那些評分和排名靠前的資料庫產品。比如,根據DB-Engines按資料庫類別的調查統計和評分圖表(如下圖1)顯示:在最近的2年裡,時序資料庫(TSDB)位居增長最快的資料庫型別榜首,尤其是最近一年時間裡,更是一騎絕塵!

圖1

從DB-Engines關於TSDB的評分趨勢圖(如下圖2)來看,主流的TSDB包括了InfluxDB、Prometheus、TimescaleDB、Apache Druid、OpenTSDB等等。

圖2

事實上,業界流行的ClickHouse、Apache IoTDB等也屬於時序資料庫範疇。本文從應用運維場景,對眾多的TSDB做個初步分析和篩選出典型代表產品,方便後面進行鍼對性的對比分析。

  • InfluxDB:排名第一,社群火熱和國內外採用廠商比較多。
  • Prometheus:屬於CNCF基金會第二個畢業的專案,在社群中比較火爆,甚至在容器領域形成事實的監控預設方案。在國內外被普遍採用。
  • TimescaleDB: 基於優秀的PostgreSQL構建出的時序資料庫。長遠考慮,專業的TSDB必須是從底層儲存面向時序資料的特徵進行鍼對性設計和優化的。因此它不在本文中進一步分析。
  • Apache Druid:非常有名的實時OLAP分析平臺,面向時序資料設計的,在極致效能和資料schema的靈活性方面有一定的平衡。類似的產品還有Pinot、Kylin等。
  • OpenTSDB:基於HBase構建的時序資料庫,依賴Hadoop生態太重,早期和InfluxDB並駕齊驅;近年來在社群中的熱度已經遠遠落後於InfluxDB了。它還不支援多維查詢。因此,它也排除在外。
  • ClickHouse:俄羅斯Yandex開發的資料分析資料庫(OLAP),但它可以充當TSDB來使用。本文不做深入分析。
  • IoTDB:國內清華大學開源的時序資料庫,面向工業IoT場景;效能出眾,社群活躍。

結合國內使用者和社群熱度情況,本文挑選出具有代表性的InfluxDB、Prometheus、Druid、和IoTDB來進一步分析它們的儲存核心。

運維域的時序資料的特性:

• 不可變性(Immutable)

• 實時性(realtime),歷史越久遠的資料,其潛在價值越小。一方面是流式寫入,一方面是近實時查詢或即時分析。

• 海量(Volumne)某直播平臺,高速實時寫入2000萬/s; 需要結構化的資料多達200TB/d。如果考慮雲服務廠商的某些邏輯多租的時序資料庫應用,對峰值寫入和峰值查詢有更高的要求。

• 高壓縮率:資料量太大直接影響到儲存成本,所以高效能資料壓縮是必備特性。

時序資料模型

在本文展開之前,先羅列出一些專業術語,以方便統一認知。說實話,就是資料庫或者運維領域的專業人士,也經常被各種中文翻譯搞得一頭霧水。為了減少歧義性,本文習慣性地在一些關鍵詞後面備註一下對應的原英文術語,以方便大家理解。

基本概念

Time series(時間序列,簡稱時序或者時序資料):根據wiki百科[2],其數學定義是這樣:In mathematics, a time series is a series of data points indexed (or listed or graphed) in time order. Most commonly, a time series is a sequence taken at successive equally spaced points in time. Thus it is a sequence of discrete-time data. 翻譯過來的要點就是 1)源於數學學科; 2)是按時間順序索引的一系列資料點。因此也多翻譯為“時序資料”。3)最常見的是在連續的相等間隔時間點上獲取的序列。4)是一個離散時間的資料序列。

Metric(指標):在軟體領域,Metric是對軟體或其規格的某些屬性的度量。在wiki百科中有這樣的闡述:software metric[3]是衡量軟體系統或過程具有某種屬性的程度的標準。儘管學術界最初認為Metric是函式(function),Measurement是通過應用metric獲得的數值;但隨著計算機學科和傳統學科的借鑑融合,這兩個術語通常也用作同義詞,泛指同一個東西了。

二者的關係:簡單地講,帶有時間戳的很多metric放在一起就構成了一個Time series。

時序資料一般有以下幾個顯著特點:

• 每條資料必然自帶時間戳,資料以時間排序

• 不可變性(immutable):一旦寫入,基本不做修改或單條刪除。(因為老化過期可以做刪除)

• 資料量大,一般要求支援PB級別。同時也要求高吞吐能力。

• 高效的儲存壓縮效率,降低成本

• 時序最核心的用途在於資料分析,包括降取樣、資料插值和空間聚合計算等

• 時序的唯一性:某一個時刻的某個指標只有一條資料(或點),即時出現多條資料也會被認為是同一條資料(或點)

• 單條資料並不重要

OpenMetrics規範

OpenMetrics[4]:一種雲原生、高度可擴充套件的指標協議。它定義了大規模上報雲原生指標的事實標準,同時支援文字表示協議和Protocol Buffers協議。雖然時間序列可以支援任意字串或二進位制資料,但RFC只針對和包括數字資料。得益於Prometheus的流行,作為Prometheus的監控資料採集方案,OpenMetrics可能很快會成為未來監控的業界標準。

目前絕大部分熱門開源服務均有官方或非官方的exporter可供使用。實施者必須以 OpenMetrics 文字格式公開指標,以響應對給定程序或裝置的文件化 URL 的簡單 HTTP GET 請求。這個端點應該被稱為“/metrics”。實施者還可以通過其他方式公開 OpenMetrics 格式的指標,例如通過 HTTP 定期將指標集推送到操作員配置的端點。

備註:事件(Event)與指標相反,單一事件發生在特定時刻;而指標是個時間序列。這個概念在運維域非常重要。

資料模型

  • OpenMetrics對資料模型[5]有如下的定義:
  • 度量值(value):它必須是浮點數或整數。
  • 時間戳(timestamp):必須是以秒為單位的 Unix Epoch。
  • 字串(string):必須僅由有效的 UTF-8 字元組成
  • 標籤(Label):由字串組成的鍵值對。以下劃線開頭的標籤名稱是保留的,一般不得使用。
  • 標籤集(LabelSet):它必須由標籤組成並且可以為空。標籤名稱在標籤集中必須是唯一的。
  • 指標點(MetricPoint):每個MetricPoint 由一組值組成,具體取決於 MetricFamily 型別。MetricPoints 不應該有明確的時間戳。
  • 指標(metric):由 MetricFamily 中的唯一 LabelSet 定義。Metrics 必須包含一個或多個 MetricPoints 的列表。給定 MetricFamily 具有相同名稱的度量標準應該在它們的 LabelSet 中具有相同的標籤名稱集。如果為一個 Metric 公開了多個 MetricPoint,則其 MetricPoint 必須具有單調遞增的時間戳。
  • 指標家族(又譯作“指標系列”, MetricFamily):一個 MetricFamily 可以有零個或多個指標。MetricFamily 必須具有名稱、HELP、TYPE 和 UNIT 元資料。MetricFamily 中的每個 Metric 都必須有一個唯一的 LabelSet。
    MetricFamily 名稱是一個字串,並且在 MetricSet 中必須是唯一的。
    字尾:OpenMetrics定義了文字格式樣例度量名稱使用的字尾(不同資料型別的字尾有所不同)有:
    計數器Counter:'_total','_created'
    摘要Summary:'_count'、'_sum'、'_created'
    直方圖Histogram:'_count'、'_sum'、'_bucket'、'_created'
    GaugeHistogram: '_gcount', '_gsum', '_bucket'
    資訊Info:'_info'
    型別指定 MetricFamily 型別。有效值有8種指標型別(參考後文)。
  • 指標集(MetricSet):是 OpenMetrics 公開的頂級物件。它必須由 MetricFamilies 組成。每個 MetricFamily 名稱必須是唯一的。相同的標籤名稱和值不應出現在 MetricSet 中的每個 Metric 上。MetricSet 中不需要特定的 MetricFamilies 排序。

儘管OpenMetric對一些概念定義得比較瑣碎和細緻,甚至晦澀難懂;但從大邏輯思路上看,它仍然包括了時間戳、指標、標籤以及基礎資料型別幾個方面,基本符合大家的日常思路。

指標型別(Metric Type)

OpenMetrics規範定義了8種指標型別:

Gauge(儀表讀數,中文翻譯不準確):它是當前的測量值,例如當前CPU的利用率或者記憶體位元組數大小。對於Gauge,使用者(我們)感興趣的是其絕對值。通俗地講,Gauge型別的指標就像我們汽車儀表盤中的指標所對應的當前數值(有增有減或者不動,因此是可變的;數值是大於零的)。Metric 中型別為 Gauge 的 MetricPoint 必須是單個值(相對於儀表盤指標不可能同時指到多個刻度位置)。

Counter(計數器):它是計量離散事件的。MetricPoint 必須具有一個稱為 Total 的值。Total必須從 0 開始隨時間單調非遞減。一般而言,使用者感興趣的主要是Counter隨時間增加的速度。

StateSet(狀態集):StateSet 表示一系列相關的布林值,也稱為位集。StateSet 度量的一個點可能包含多個狀態,並且每個狀態必須包含一個布林值。狀態有一個字串名稱。

Info(資訊指標):資訊指標用於公開在流程生命週期內不應更改的文字資訊。常見示例是應用程式的版本、修訂控制提交和編譯器的版本。資訊可用於編碼其值不隨時間變化的 ENUM,例如網路介面的型別。

Histogram(直方圖):直方圖測量離散事件的分佈。常見示例是 HTTP 請求的延遲、函式執行時或 I/O 請求大小。直方圖 MetricPoint 必須至少包含一個桶,並且應該包含 Sum 和 Created 值。每個桶必須有一個閾值和一個值。

GaugeHistogram(儀表直方圖):測量當前分佈。常見的例子是專案在佇列中等待的時間,或者佇列中請求的大小。

Summary(摘要):Summary測量離散事件的分佈,並且可以在直方圖計算過於昂貴或平均事件大小足夠時使用。包含 Count 或 Sum 值的型別為 Summary 的 Metric 中的 MetricPoint 應該具有名為 Created 的 Timestamp 值。這可以幫助攝取者區分新的指標和之前沒有看到的長期執行的指標。

Unknown(未知):當無法確定來自 3rd 方系統的單個指標的型別時,可以使用未知。一般情況下不能使用。

通俗地講,histogram用於表示一段時間內對資料的取樣,按照指定的時間間隔及總數進行統計。它是需要按照統計區間進行計算的。而Summary用於表示一段時間內資料取樣結果,直接儲存分位數(quantile)資料,不需要計算。本質上Summary是與histogram類似的。更多詳細情況可以參考官方文件[6]。

基於標籤(tag-value)的時序資料模型

當前主流TSDB的時序資料模型都是以標籤(tag,也稱label)為主來唯一確定一個時間序列(一般也附加上指標名稱、時間戳等)。

Prometheus時序資料模型

本文從CNCF社群最流行的Prometheus監控系統來分析時序資料的建模。Prometheus採用了多維資料模型,包含指標名稱(metric name)、一個或多個標籤(labels,與tags意義相同)以及指標數值(metric value)。

時序資料模型包括了metric name、一個或多個labels(同tags)以及metric value。metric name加一組labels作為唯一標識,來定義time series,也就是時間線。

Prometheus的指標模型定義如下:

<metric name>{<label name>=<label value>, ...}

指標名稱(metric name):表示了被測系統的一般特徵,即一個可以度量的指標。它採用一個通用普遍的名稱來描述一個時間序列的,比如sys.cpu.user、 stock.quote、 env.probe.temp和http_requests_total, 其中http_requests_total可以表示請求接收到的HTTP的總數。

標籤(label):由Prometheus 的維度資料模型來支撐實現。相同指標名稱的任何給定標籤組合標識該指標的特定維度例項。更改任何標籤值,包括新增或刪除標籤,都會建立一個新的時間序列。因此通過標籤可以讓查詢語言輕鬆實現過濾、分組和匹配。

樣本(Sample):按照某個時序以時間維度採集的資料,稱之為樣本。實際的時間序列,每個序列包括一個float64的值和一個毫秒級的Unix時間戳。本質上屬於單值模型。

單值模型的時間序列/時間線(time series): 具有相同指標名稱和相同標籤維度集合的帶有時間戳數值的資料流。通俗地講,就是用metric name加一組labels作為唯一標識,來定義時間線。

圖3

上圖3是某個時間段內的相關資料點的分佈示意圖[7],其中橫軸是時間,縱軸是時間線,區域內每個點就是資料點。指標名稱和一組標籤唯一確定一條時間線(就是每條水平線)。在同一時刻,每條時間線只會產生一個數據點,但同時會有多條時間線產生資料,把這些資料點連在一起,就是一條豎線。因此,Prometheus每次接收資料,收到的是圖中縱向的一條線。這些水平線和豎線的特徵很重要,影響到數值插值,以及資料寫入和壓縮的優化策略。

InfluxDB時序資料模型

下圖4是InfluxDB對時序資料模型的圖形化表示:

圖4

measurement:
指標物件,也即一個數據源物件。每個measurement可以擁有一個或多個指標值,也即下文所述的field。在實際運用中,可以把一個現實中被檢測的物件(如:“cpu”)定義為一個measurement。measurement是fields,tags以及time列的容器,measurement的名字用於描述儲存在其中的欄位資料,類似mysql的表名。

tags:
概念等同於大多數時序資料庫中的tags, 通常通過tags可以唯一標示資料來源。每個tag的key和value必須都是字串。

field:
資料來源記錄的具體指標值。每一種指標被稱作一個“field”,指標值就是 “field”對應的“value”。fields相當於SQL的沒有索引的列。

timestamp:
資料的時間戳。在InfluxDB中,理論上時間戳可以精確到 納秒(ns)級別

每個Measurement內的資料,從邏輯上來講,會組織成一張大的資料表(如下圖5)。Tag用於描述Measurement,而Field用於描述Value。從內部實現來上看,Tag會被全索引,而Filed不會。

圖5

多值模型下的時間線(Series):在討論Series之前,先看看一個series key的定義:共享measurement,標記集合和field key的資料點的集合。它是InfluxDB的核心概念之一。比如上圖中,census,location=klamath,scientist=anderson bees構成一個series key。因此上圖中有2個series key。而Series就是針對給定的series key對應的時間戳和欄位值。比如上圖中,series key為census,location=klamath,scientist=anderson bees的series就是:

2019-08-18T00:00:00Z 23

2019-08-18T00:06:00Z 28

所以,InfluxDB中的series key可以理解為我們通常所說的時間線(或者時間線的key),而series就是時間線所包含的值(相當於資料點)。二者都泛指TSDB中的時間序列/時間線,只是從key-value對的角度進行了邏輯概念區分。

小結:如下圖6所示,時序資料一般分為兩部分,一個是識別符號(指標名稱、標籤或維度),方便搜尋與過濾;一個是資料點,包括時間戳和度量數值。數值主要是用作計算,一般不建索引。從資料點包含數值的多少,可以分為單值模型(比如Prometheus)和多值模型(比如InfluxDB);從資料點儲存方式來看,有行儲存和列儲存之分。一般情況下,列存能有更好的壓縮率和查詢效能。

圖6

基於樹形(tree schema)的時序資料模型

IoTDB與其他TSDB的資料模型最大的不同,沒有采用標籤(tag-value、Labels)模式,而是採用樹形結構定義資料模式:以root為根節點、把儲存組、裝置、感測器串聯在一起的樹形結構,從root根節點經過儲存組、裝置到感測器葉子節點,構成了一條路徑(Path)。一條路徑就可以命名一個時間序列,層次間以“.”連線。如下圖7所示[8]:

圖7

資料點(Data point):一個“時間-值”對。

時間序列(一個實體的某個物理量對應一個時間序列,Timeseries,也稱測點 meter、時間線 timeline,實時資料庫中常被稱作標籤 tag、引數 parameter):一個物理實體的某個物理量在時間軸上的記錄,是資料點的序列。類似於關係資料庫中的一張表,不過這張表主要有時間戳(Timestamp)、裝置ID(Device ID)、測點值(Measurement)三個主要欄位;另外還增加了Tag和Field等擴充套件欄位,其中Tag支援索引,Field不支援索引。

IoTDB這種基於樹的模式(tree schema)和其它TSDB很不一樣,有以下優點:

  • 裝置管理是層次化的:比如許多工業場景裡裝置管理不是扁平的,而是有層次的。其實在應用軟體體系中也是類似的場景,比如CMDB就維護著軟體元件或資源之間的一種層次關係。所以IoTDB認為基於tree schema 比基於 tag-value schema更合適IoT場景。
  • 標籤及其值的相對不變性:在大量實際應用中,標籤的名字及其對應的數值是不變的。例如:風力發電機制造商總是用風機所在的國家、所屬的風場以及在風場中的 ID 來標識一個風機,因此,一個 4 層高的樹(“root.the-country-name.the-farm-name.the-id”)就能表示清楚,而且很簡潔;一定程度減少了資料模式的重複描述。
  • 靈活查詢:基於路徑的時間序列 ID 定義,比較方便靈活的查詢,例如:”root.*.a.b.*“,其中、*是一個萬用字元。

各TSDB的概念對比

首先從RDB視角來對比對映主流TSDB的基本概念,以方便大家理解。

表1

從上面表1可以看出,database邏輯概念更多地體現了一種資料schema定義,方便資料的邏輯組織劃分(比如InfluxDB的database)、管理(比如Druid的3種schema定義)和儲存(比如IoTDB的storage group)。另外OpenMetric屬於指標規範,更多地體現關於資料點的定義和邏輯細節的管理(比如MetricSet、MetricFamilies、MetricPoint、LabelSet等,搞得很細也很複雜)。

其次,我們從時序資料集中的每個資料點或者一行資料的角度來分析,以下圖8為例。

圖8

時序資料的基本模型可以分成下面幾個部分:

Metric:度量的資料集,類似於關係型資料庫中的 table,是固定屬性,一般不隨時間而變化

Timestamp:時間戳,表徵採集到資料的時間點

Tags:維度列,用於描述Metric,代表資料的歸屬、屬性,表明是哪個裝置/模組產生的,一般不隨著時間變化

Field/Value:指標列,代表資料的測量值,可以是單值也可以是多值

圍繞上述時序資料模型,我們對比看看各種TSDB中基本概念的對應關係,如下表2所示:

表2

OpenMetric是關於指標的社群規範,還在持續演變中,還每正式成為IETF標準的一部分。當前看,它的建模過於細節(從而概念之間交叉模糊,不易理解)。反而是TSDB經過多年的實踐,關於時序資料的模型抽象更直接和高效。

參考資料

[1]    https://db-engines.com/en/

[2]    https://en.wikipedia.org/wiki/Time_series

[3]    https://en.wikipedia.org/wiki/Software_metric

[4]    https://openmetrics.io/

[5]    https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md

[6]    https://prometheus.io/docs/practices/histograms/

[7]    Fabian Reinartz, https://fabxc.org/tsdb/

[8]    https://bbs.huaweicloud.com/blogs/280943

gs/280943

點選關注,第一時間瞭解華為雲新鮮技術~