不同數據庫處理高基數數據的方式,你會嗎?
了解不同數據庫如何處理高基數數據,并了解選擇正確的索引方案為何如此重要。
譯自How Different Databases Handle High-Cardinality Data,作者 Team Timescale。
時間序列數據、物聯網傳感器讀數、用戶行為日志——這些只是現代系統必須處理的數據流的幾個例子。它們的共同點是都傾向于高基數,這給數據存儲和分析帶來了獨特的挑戰。隨著組織越來越依賴數據驅動的決策,了解不同數據庫如何處理高基數數據對于構建高效且可擴展的系統至關重要。
本文將探討高基數數據帶來的挑戰,檢查旨在處理高基數數據的各種數據庫工具,并比較各種方法,以幫助您做出關于數據架構的明智決策。
高基數的挑戰
高基數指的是數據集中唯一元素的數量,當我們查看現實世界的例子時,這是一個特別具體的概念。想象一下一個跟蹤熱門網站上用戶交互的系統——每個用戶可能都有一個唯一的標識符,每個會話都會生成一個唯一的ID,每個交互都會創建一個唯一的事件ID。在大規模應用中,這些唯一值可以迅速達到數百萬甚至數十億。
這種大量唯一值會給數據庫系統帶來重大挑戰。當在具有高基數列的表之間執行連接時,潛在的組合會呈指數級增長。例如,將用戶交互數據與會話數據連接可能需要將數百萬個唯一的用戶ID與數百萬個唯一的會話ID進行匹配。由于數據庫必須維護和處理這些海量獨特的組合,因此生成的運算會迅速壓垮系統資源。
在需要完全表掃描的操作中,性能下降尤其嚴重。當數據庫需要跨高基數列分析或聚合數據時,它必須在內存中為每個唯一值維護不同的計數器或聚合。這會迅速耗盡可用的內存資源,導致查詢執行時間變慢,或者在極端情況下導致系統故障。
閱讀本文以了解更多關于高基數的信息。
數據庫解決方案:時間序列數據庫InfluxDB和TimescaleDB如何處理高基數
鑒于高基數數據集在時間序列中有多么常見,讓我們來看看兩個時間序列數據庫InfluxDB和TimescaleDB是如何處理這個問題的。
InfluxDB是一個NoSQL數據庫,其創建者選擇從頭開始重建所有內容。相比之下,TimescaleDB是一個SQL數據庫,其創建者(即本文作者)選擇擁抱并構建在PostgreSQL和已驗證的數據結構之上,然后進一步擴展它以用于時間序列、事件和實時分析問題。(順便說一句,使用正確的擴展,它還可以推動您的AI應用程序開發。)
首先,以下是這兩個數據庫在數據集基數增加時插入性能的比較。
對于以下比較,我們使用了以下設置:
- TimescaleDB版本1.2.2,InfluxDB版本1.7.6
- 1臺遠程客戶端機器和1臺數據庫服務器,兩者都在同一個云數據中心
- AWS EC2實例:i3.xlarge(4個vCPU,30 GB內存)
- 4個1 TB磁盤,采用raid0配置(EXT4文件系統)
- 兩個數據庫都獲得了所有可用內存
- 數據集:100-1,000,000個模擬設備每10秒生成1-10個CPU指標,約1億個讀取間隔,約10億個指標(100個設備一個月間隔;4000個設備三天;100,000個設備三個小時;1,000,000個設備三分鐘),使用時間序列基準套件 (TSBS) 生成- 用于TimescaleDB (1)和InfluxDB (2)的模式
- 插入時兩個數據庫都使用了10K批大小
- 對于TimescaleDB,我們根據數據量設置塊大小,目標是10-15個塊(更多信息)
- 對于InfluxDB,我們啟用了TSI(時間序列索引)
(1)TimescaleDB schema:Tablecpu(time timestamp, tags_id integer, usage_user double, usage_system double, usage_idle double, usage_nice double, usage_iowait double, usage_irq double, usage_softirq double, usage_steal double, usage_guest double, usage_guest_nice double, additional_tags jsonb); indexes (tags_id, time) and (time, tags_id); Tabletags(id integer, hostname text, region text, datacenter text, rack text, os text, arch text, team text, service text, service_version text, service_environment text); unique index on all columns
(2)InfluxDB schema:Field keys (usage_guest integer, usage_guest_nice integer, usage_idle integer, usage_iowait integer, usage_irq integer, usage_nice integer, usage_softirq integer, usage_steal integer, usage_system integer, usage_user integer), Tag keys (arch, datacenter, hostname, os, rack, region, service, service_environment, service_version, team)
圖片
注意:這里可以找到這兩個數據庫更詳細的總體比較。
正如你所看到的,在低基數情況下,兩個數據庫是可比的(盡管 TimescaleDB 的性能高出 30%)。但隨著基數的增加,差異變得相當顯著,因為 TimescaleDB 的插入性能下降速度遠遠慢于 InfluxDB,而 InfluxDB 的性能則急劇下降。在高基數情況下,TimescaleDB 的性能比 InfluxDB 高出 11 倍以上。
這些結果對一些人來說可能并不令人驚訝,因為高基數是 InfluxDB 的一個眾所周知的弱點(來源:GitHub、論壇)。
但為什么會這樣呢?讓我們更仔細地看看這兩種數據庫的開發情況。
B-Trees 與TSI:處理高基數的兩種不同方法
我們可以將高基數性能的差異追溯到InfluxDB與TimescaleDB在工程決策上的根本不同。
InfluxDB 和 TSI
由于高基數一直是InfluxDB的一個眾所周知的挑戰,他們的團隊一直在研究一種稱為“時間序列索引”(TSI)的東西來解決這個問題。
與他們在其他領域的做法一致,InfluxDB TSI 是一個基于本地日志結構合并樹的系統,由各種數據結構組成,包括哈希映射和位集。這包括一個內存中的日志(“LogFile”),當其超過閾值(5 MB)時會定期刷新到磁盤,并且被壓縮到一個磁盤上的內存映射索引(“IndexFile”);一個文件(“SeriesFile”),包含了整個數據庫中所有序列鍵的集合。(在他們的文檔中有描述。)
TSI 的性能取決于所有這些數據結構的相互作用。然而,由于 TSI 是定制構建的,理解其在各種高基數工作負載下的表現變得難以理解。
TSI 的設計決策也導致了一些具有性能影響的限制:
- 根據InfluxDB的文檔,該總基數限制大約為3,000萬(盡管根據上面的圖表,InfluxDB在達到該限制之前就已經開始表現不佳),或者遠低于物聯網(包括我們上面的示例)等時間序列用例中通常所需的數量。
- InfluxDB索引標簽但不索引字段,這意味著某些查詢無法比全表掃描表現得更好。因此,以我們之前提到的物聯網數據集為例,如果想要搜索所有沒有空閑內存的行(例如,類似于SELECT * FROM sensor_data WHERE mem_free = 0的查詢),就無法比全表線性掃描(即O(n)時間)做得更好來識別相關數據點。
- 索引中包含的列集是完全固定且不可變的。更改數據中哪些列被索引(標記)以及哪些沒有,需要完全重寫數據。
- 由于依賴哈希映射,InfluxDB 只能索引離散值而不能索引連續值。例如,要搜索所有溫度高于 90 度的行(例如,類似于 SELECT * FROM sensor_data WHERE temperature > 90 的查詢),則需要再次完全掃描整個數據集。
- InfluxDB 的基數受到所有時間范圍內基數的影響,即使某些字段/值不再存在于數據集中也是如此。這是因為 SeriesFile 存儲了整個數據集的所有系列鍵。
TimescaleDB 和 B-trees
相比之下,TimescaleDB是一個關系型數據庫,它依賴于久經考驗的用于索引數據的結構:B-tree。這一決定使其能夠擴展到高基數。
首先,TimescaleDB按時間對您的數據進行分區,一個B-tree將時間段映射到相應的分區(“chunk”)。所有這些分區都在后臺進行,對用戶隱藏,用戶能夠訪問一個虛擬表(“hypertable”),該表跨越所有分區中的所有數據。
接下來,TimescaleDB允許在您的數據集上創建多個索引(例如,對于equipment_id、sensor_id、firmware_version、site_id)。默認情況下,這些索引以B-tree的形式在每個chunk上創建。
也可以使用任何內置的PostgreSQL索引類型創建索引:Hash、GiST、SP-GiST、GIN和BRIN。您可以閱讀這篇文章以了解有關索引的更多信息以及如何使用它們來優化PostgreSQL數據庫性能。
這種方法對高基數數據集有一些好處:
- 更簡單的方法可以更清晰地了解數據庫的性能。只要我們要查詢的數據集的索引和數據適合內存(這是可以調整的),基數就成為一個非問題。
- 此外,由于輔助索引的范圍在chunk級別,因此索引本身的大小僅與該時間范圍的數據集的基數一樣大。
- 您可以控制要索引的列,包括能夠在多列上創建復合索引。您也可以隨時添加或刪除索引,例如,如果您的查詢工作負載發生變化。與InfluxDB不同,在TimescaleDB中更改索引結構不需要重寫數據的整個歷史記錄。
- 您可以對離散字段和連續字段創建索引,特別是由于B-tree非常適合使用以下任何運算符進行比較:<、<=、=、>=、>、BETWEEN、IN、IS NULL、IS NOT NULL。我們上面示例查詢(SELECT * FROM sensor_data WHERE mem_free = 0和SELECT * FROM sensor_data WHERE temperature > 90)將在對數時間或O(log n)時間內運行。
- 其他受支持的索引類型在其他場景中可能派上用場,例如,用于“最近鄰”搜索的GIST索引。
結論
現代數據庫系統中高基數數據帶來的挑戰需要復雜的索引解決方案來克服連接操作和全表掃描的固有障礙。InfluxDB和Timescale都具有獨特的策略來有效地管理高基數數據。
Timescale的方法利用了B-tree數據結構的強大功能,為處理高基數數據集提供了強大的基礎。這種結構不僅能夠實現卓越的查詢性能,而且還提供了滿足各種索引需求所需的靈活性。B-tree架構允許高效的范圍查詢和點查找,使其特別適合時間序列應用程序,在這些應用程序中,歷史分析和實時數據訪問都至關重要。