本文來自網易雲社區

作者:范欣欣

在上篇文章《時序資料庫體系技術(一):時序數據存儲模型設計》中筆者分別介紹了多種時序資料庫在存儲模型設計上的一些考慮,其中OpenTSDB基於HBase對維度值進行了全局字典編碼優化,Druid採用列式存儲並實現了Bitmap索引以及局部字典編碼優化,InfluxDB和Beringei都將時間線挑了出來,大大降低了Tag的冗餘。在這幾種時序資料庫中,InfluxDB無疑顯的更加專業。接下來筆者將會針對InfluxDB的基本概念、內核實現等進行深入的分析。本篇文章先行介紹一些相關的基本概念。

InfluxDB 數據模型

InfluxDB的數據模型和其他時序資料庫有些許不同,下圖是InfluxDB中的一張示意表:

1. Measurement:從原理上講更像SQL中表的概念。這和其他很多時序資料庫有些不同,其他時序資料庫中Measurement可能與Metric等同,類似於下文講到的Field,這點需要注意。

2. Tags:維度列

(1)上圖中location和scientist分別是表中的兩個Tag Key,其中location對應的維度值Tag Values為{1, 2},scientist對應的維度值Tag Values為{langstroth, perpetual},兩者的組合TagSet有四種:

location = 1 , scientist = langstroth
location = 1 , scientist = perpetual
location = 2 , scientist = langstroth
location = 2 , scientist = perpetual

(2)在InfluxDB中,表中Tags組合會被作為記錄的主鍵,因此主鍵並不唯一,比如上表中第一行和第三行記錄的主鍵都為』location=1,scientist=langstroth』。所有時序查詢最終都會基於主鍵查詢之後再經過時間戳過濾完成。

3. Fields:數值列。數值列存放用戶的時序數據。

4. Point:類似SQL中一行記錄,而並不是一個點。

InfluxDB 核心概念 – Series

文章《時序資料庫體系技術(一) – 時序數據存儲模型設計》中提到時間線的概念,時序數據的時間線就是一個數據源採集的一個指標隨著時間的流逝而源源不斷地吐出數據,這樣形成的一條數據線稱之為時間線。如下圖所示:

上圖中有兩個數據源,每個數據源會採集兩種指標:butterflier和honeybees。InfluxDB中使用Series表示數據源,Series由Measurement和Tags組合而成,Tags組合用來唯一標識Measurement。Series是InfluxDB中最重要的概念,在接下來的內核分析中會經常用到。

InfluxDB 系統架構

InfluxDB對數據的組織和其他資料庫相比有很大的不同,為了更加清晰的說明,筆者按照自己的理解畫了一張InfluxDB邏輯架構圖:

DataBase

InfluxDB中有Database的概念,用戶可以通過create database xxx來創建一個資料庫。

Retention Policy(RP)

數據保留策略。很長一段時間筆者對RP的理解都不足夠充分,以為RP只規定了數據的過期時間。其實不然,RP在InfluxDB中是一個非常重要的概念,核心作用有3個:指定數據的過期時間,指定數據副本數量以及指定ShardGroup Duration。RP創建語句如下:

CREATE RETENTION POLICY ON <retention_policy_name> ON <database_name> DURATION <duration> REPLICATION <n> [SHARD DURATION <duration> ] [DEFAULT]

其中retention_policy_name表示RP的名稱,database_name表示資料庫名稱,duration表示TTL,n表示數據副本數。SHARD DURATION下文再講。舉個簡單的栗子:

CREATE RETENTION POLICY "one_day_only" ON "water_database" DURATION 1d REPLICATION 1 SHARD DURATION 1h DEFAULT

InfluxDB中Retention Policy有這麼幾個性質和用法:

1. RP是資料庫級別而不是表級別的屬性。這和很多資料庫都不同。

2. 每個資料庫可以有多個數據保留策略,但只能有一個默認策略。

3. 不同表可以根據保留策略規劃在寫入數據的時候指定RP進行寫入,下面語句就指定six_mouth_rollup的rp進行寫入:

curl -X POST http://localhost:8086/write?db=mydb&rp=six_month_rollup -->disk_free,hostname=server01 value=442221834240i 1435362189575692182

如果沒有指定任何RP,則使用默認的RP。

Shard Group

Shard Group是InfluxDB中一個重要的邏輯概念,從字面意思來看Shard Group會包含多個Shard,每個Shard Group只存儲指定時間段的數據,不同Shard Group對應的時間段不會重合。比如2017年9月份的數據落在Shard Group0上,2017年10月份的數據落在Shard Group1上。

每個Shard Group對應多長時間是通過Retention Policy中欄位」SHARD DURATION」指定的,如果沒有指定,也可以通過Retention Duration(數據過期時間)計算出來,兩者的對應關係為:

問題來了,為什麼需要將數據按照時間分成一個一個Shard Group?個人認為有兩個原因:

1. 將數據按照時間分割成小的粒度會使得數據過期實現非常簡單,InfluxDB中數據過期刪除的執行粒度就是Shard Group,系統會對每一個Shard Group判斷是否過期,而不是一條一條記錄判斷。

2. 實現了將數據按照時間分區的特性。將時序數據按照時間分區是時序資料庫一個非常重要的特性,基本上所有時序數據查詢操作都會帶有時間的過濾條件,比如查詢最近一小時或最近一天,數據分區可以有效根據時間維度選擇部分目標分區,淘汰部分分區。

Shard

Shard Group實現了數據分區,但是Shard Group只是一個邏輯概念,在它裡面包含了大量Shard,Shard才是InfluxDB中真正存儲數據以及提供讀寫服務的概念,類似於HBase中Region,Kudu中Tablet的概念。關於Shard,需要弄清楚兩個方面:

1. Shard是InfluxDB的存儲引擎實現,具體稱之為TSM(Time Sort Merge Tree) Engine,負責數據的編碼存儲、讀寫服務等。TSM類似於LSM,因此Shard和HBase Region一樣包含Cache、WAL以及Data File等各個組件,也會有flush、compaction等這類數據操作。

2. Shard Group對數據按時間進行了分區,那落在一個Shard Group中的數據又是如何映射到哪個Shard上呢?

InfluxDB採用了Hash分區的方法將落到同一個Shard Group中的數據再次進行了一次分區。這裡特別需要注意的是,InfluxDB是根據hash(Series)將時序數據映射到不同的Shard,而不是根據Measurement進行hash映射,這樣會使得相同Series的數據肯定會存在同一個Shard中,但這樣的映射策略會使得一個Shard中包含多個Measurement的數據,不像HBase中一個Region的數據肯定都屬於同一張表。

InfluxDB Sharding策略

上文已經對InfluxDB的Sharding策略進行了介紹,這裡簡單地做下總結。我們知道通常分散式資料庫一般有兩種Sharding策略:Range Sharding和Hash Sharding,前者對於基於主鍵的範圍掃描比較高效,HBase以及TiDB都採用的這種Sharding策略;後者對於離散大規模寫入以及隨即讀取相對比較友好,通常最簡單的Hash策略是採用取模法,但取模法有個很大的弊病就是取模基礎需要固定,一旦變化就需要數據重分布,當然可以採用更加複雜的一致性Hash策略來緩解數據重分布影響。

InfluxDB的Sharding策略是典型的兩層Sharding,上層使用Range Sharding,下層使用Hash Sharding。對於時序資料庫來說,基於時間的Range Sharding是最合理的考慮,但如果僅僅使用Time Range Sharding,會存在一個很嚴重的問題,即寫入會存在熱點,基於Time Range Sharding的時序資料庫寫入必然會落到最新的Shard上,其他老Shard不會接收寫入請求。對寫入性能要求很高的時序資料庫來說,熱點寫入肯定不是最優的方案。解決這個問題最自然的思路就是再使用Hash進行一次分區,我們知道基於Key的Hash分區方案可以通過散列很好地解決熱點寫入的問題,但同時會引入兩個新問題:

1. 導致Key Range Scan性能比較差。InfluxDB很優雅的解決了這個問題,上文筆者提到時序資料庫基本上所有查詢都是基於Series(數據源)來完成的,因此只要Hash分區是按照Series進行Hash就可以將相同Series的時序數據放在一起,這樣Range Scan性能就可以得到保證。事實上InfluxDB正是這樣實現的。

2. Hash分區的個數必須固定,如果要改變Hash分區數會導致大量數據重分布。除非使用一致性Hash演算法。筆者看到InfluxDB源碼中Hash分區的個數固定是1,對此還不是很理解,如果哪位看官對此比較熟悉可以指導一二。

總結

本篇文章重點介紹InfluxDB中一些基本概念,為後面分析InfluxDB內核實現奠定一個基礎。文章主要介紹了三個重要模塊:

1. 首先介紹了InfluxDB中一些基本概念,包括Measurement、Tags、Fields以及Point。

2. 接著介紹了Series這個非常非常重要的概念。

3. 最後重點介紹了InfluxDB中數據的組織形式,總結起來就是:先按照RP劃分,不同過期時間的數據劃分到不同的RP,同一個RP下的數據再按照時間Range分區形成ShardGroup,同一個ShardGroup中的數據再按照Series進行Hash分區,將數據劃分成更小粒度的管理單元。Shard是InfluxDB中實際工作者,是InfluxDB的存儲引擎。

原文:時序資料庫技術體系(二):初識InfluxDB ,經作者范欣欣授權發布

了解網易雲 :

網易雲官網:https://www.163yun.com

網易雲免費體驗館,0成本體驗20+款雲產品!

更多網易研發、產品、運營經驗分享請訪問網易雲社區。

推薦閱讀:

相关文章