一、InfluxDB 與 TSM 文件初相識
**
在數字化時代,數據量呈爆發式增長,尤其是時間序列數據,如服務器監控指標、傳感器讀數、金融交易記錄等,它們都帶有時間戳,記錄著事物隨時間的變化。InfluxDB 作為一款高性能的開源時序數據庫,在處理這些時間序列數據方面發揮著舉足輕重的作用 ,被廣泛應用于監控系統、物聯網、實時分析、金融交易監控、環境監測等諸多場景。
InfluxDB 采用 Go 語言編寫,這賦予了它出色的性能和跨平臺特性,編譯后生成的二進制文件無外部依賴,部署和運行都極為便捷。其獨特的設計專為高效存儲和查詢時間序列數據而生,在性能、功能特性等方面都展現出卓越的優勢。在性能上,它的時間結構合并樹(TSM,Time-Structured Merge Tree)存儲引擎基于日志結構化合并樹(LSM,Log-Structured Merge Tree)演變而來,針對時間序列數據的特點進行了深度優化,能夠實現高速的數據讀寫和高效的數據壓縮。在單機環境下,每秒可支持數十萬數據點的寫入操作,輕松應對大規模數據的快速寫入需求 。從功能特性來看,InfluxDB 支持類 SQL 的查詢語言 InfluxQL,讓熟悉 SQL 語法的開發者能迅速上手,方便地對時間序列數據進行查詢和分析。同時,它允許對 tag 建立索引,通過標簽可以靈活地對數據進行分組、過濾和查詢,實現快速有效的數據檢索。此外,InfluxDB 還具備豐富的聚合運算和采樣能力,提供了一系列如 MIN、MAX、SUM、COUNT、MEAN、MEDIAN 等聚合函數,方便用戶對數據進行統計分析;還支持連續查詢(CQ,Continuous Query)功能,可以自動定時執行查詢操作,并將結果存儲起來,有效減少重復計算,提高查詢效率。
在 InfluxDB 的存儲體系中,TSM 文件扮演著核心角色。它是 InfluxDB 自研的一種存儲引擎,將時序數據和索引數據一同存儲在一個文件中。在 data 文件夾下,每個數據庫都對應有一個子文件夾,而這個子文件夾里存儲的正是該數據庫的所有 TSM 文件 。這種獨特的存儲方式極大地減少了磁盤 I/O 的開銷,進而提高了查詢性能。當數據寫入 InfluxDB 時,首先會被記錄在內存中的寫入緩沖區,待緩沖區滿了或達到特定時間間隔后,數據就會被批量寫入磁盤上的 TSM 文件 。在查詢數據時,InfluxDB 會依據 TSM 文件中的索引快速定位到所需數據,從而實現高效查詢。例如,在一個實時監控系統中,需要頻繁查詢服務器的 CPU 使用率、內存利用率等指標數據,TSM 文件的高效存儲和查詢機制就能確保系統快速響應,及時為運維人員提供準確的數據支持。
二、探秘 TSM 文件管理
(一)TSM 文件結構剖析
TSM 文件主要由頭部信息(Header)、數據塊(Blocks)、索引(Index)和頁腳(Footer)這幾個關鍵部分組成,它們各司其職,共同保障了 InfluxDB 高效的數據存儲和查詢功能。
- 頭部信息:占據 5 個字節,其中 4 個字節用于存儲識別文件類型的神奇數字,就像是文件的獨特 “指紋”,能讓系統快速知曉這是一個 TSM 文件;另外 1 個字節記錄文件的版本號,便于系統在進行版本升級或兼容性處理時做出準確判斷。比如當 InfluxDB 進行版本更新,引入了新的 TSM 文件格式特性時,通過版本號就能確定該文件是否符合新特性的要求,從而進行相應的處理 。
- 數據塊:由一系列的 CRC32 校驗和與數據對構成。CRC32 校驗和就如同數據的 “保鏢”,負責在數據傳輸和存儲過程中檢測錯誤,一旦數據出現損壞或丟失,通過 CRC32 校驗和就能及時發現 。數據塊中的數據是經過壓縮處理后存儲的,這大大減少了磁盤空間的占用,提高了存儲效率。例如,在存儲大量傳感器采集的時間序列數據時,經過壓縮的數據塊能顯著降低存儲成本,同時在讀取數據時,也能快速解壓縮還原出原始數據 。
- 索引:索引部分按照鍵(包括測量名稱、標簽集和字段)然后按時間字典順序排列索引條目序列。這種有序排列的方式,就像是一本精心編排的字典,讓系統能通過索引快速定位到所需數據。例如,當我們要查詢某個特定服務器在某段時間內的 CPU 使用率時,通過索引中鍵和時間的有序排列,系統能迅速定位到包含這些數據的索引條目,進而找到對應的數據塊,大大提高了查詢效率 。每個索引條目都包含鍵長度、鍵、塊類型(如浮點型、整數型、布爾型、字符串等)、索引塊條目數、最小時間、最大時間、偏移量和大小等信息 。這些詳細的信息就像是數據的 “坐標”,通過它們可以準確地找到數據在 TSM 文件中的存儲位置 。
- 頁腳:雖然只有 4 個字節,但卻保存著索引的偏移量,這個偏移量就像是通往索引的 “鑰匙”,系統通過它可以快速定位到索引部分,從而開啟查詢數據的大門 。
(二)TSM 文件的寫入流程
數據寫入 InfluxDB 到最終寫入 TSM 文件,需要經歷一系列嚴謹的步驟。
- 寫入 WAL:當數據進入 InfluxDB 時,首先會被寫入預寫日志(WAL)。WAL 就像是一個數據的臨時 “保險柜”,它采用追加寫入的方式,將數據以固定格式存儲,確保寫入操作的持久性 。即使系統突然崩潰,也能從 WAL 中恢復未持久化到 TSM 文件的數據 。例如,在一個實時監控系統中,大量的服務器性能數據不斷涌入 InfluxDB,這些數據首先被安全地存入 WAL,為后續的處理提供了可靠保障 。每個 WAL 文件被劃分為固定大小的段,當一個段的大小達到 10MB 時,就會關閉當前段并打開一個新的段繼續寫入 。數據在寫入 WAL 時,會先進行序列化處理,然后使用 Snappy 壓縮算法進行壓縮,以減少存儲空間占用,壓縮后的數據按照 TLV 標準存儲,即單個字節表示條目的類型(寫入或刪除)、4 個字節的 uint32 表示壓縮塊的長度,然后是壓縮塊 。
- 寫入內存緩存:在數據寫入 WAL 的同時,也會被寫入內存緩存(Cache)。Cache 是 WAL 中數據在內存中的副本,它按照鍵(測量值、標簽集和唯一字段)對數據進行組織,每個字段都按自己的時間順序范圍保存 。Cache 就像是一個高速的數據 “緩沖區”,查詢操作可以直接在 Cache 中進行,提高了查詢響應速度 。當查詢運行時,寫入操作不會影響 Cache 中的數據副本,保證了查詢結果的一致性 。Cache 還設置了一些內存閾值和時間閾值來控制數據的寫入和快照操作。當 Cache 的內存使用量超過 cache - snapshot - memory - size(下限)時,會觸發將 Cache 中的數據快照寫入 TSM 文件,并刪除相應的 WAL 段;當 Cache 的內存使用量超過 cache - max - memory - size(上限)時,Cache 將拒絕新的寫入,以防止內存不足 。此外,如果在指定的時間間隔(cache - snapshot - write - cold - duration)內沒有收到寫入操作,也會強制將 Cache 中的數據快照保存到 TSM 文件 。
- 批量合并到 TSM 文件:當滿足一定條件時,比如 Cache 達到內存閾值或者經過一定的時間間隔,Cache 中的數據會被批量合并到 TSM 文件中 。這個過程就像是將分散的文件整理成一個大文件,將多個小的數據塊合并成一個大的數據塊,減少了文件數量和磁盤 I/O 操作,提高了存儲和查詢效率 。在合并過程中,還會對數據進行壓縮和優化處理,進一步減少磁盤空間占用 。例如,在每天凌晨系統負載較低時,將當天積累在 Cache 中的數據批量合并到 TSM 文件中,為后續的查詢和分析做好準備 。
(三)TSM 文件的查詢機制
InfluxDB 通過索引實現對 TSM 文件中數據的快速定位和查詢,這一過程依賴于高效的索引結構和查詢算法。
- 索引定位:當接收到查詢請求時,InfluxDB 首先會根據查詢條件在內存索引中查找對應的索引條目。內存索引就像是一個快速檢索的 “目錄”,它存儲了測量名稱、標簽集和系列等信息的索引,能快速定位到可能包含所需數據的 TSM 文件 。例如,當查詢某個特定設備在某段時間內的溫度數據時,內存索引會根據設備的標簽信息快速定位到對應的 TSM 文件 。找到對應的 TSM 文件后,會根據索引中的鍵和時間信息,在 TSM 文件的索引部分進行二分查找,進一步縮小數據范圍 。由于 TSM 文件索引中的條目是按鍵和時間字典順序排列的,二分查找能夠快速定位到包含所需數據的索引條目,從而確定數據所在的數據塊位置 。
- 數據讀取:確定數據塊位置后,通過索引條目中記錄的偏移量和大小信息,就可以從 TSM 文件中讀取相應的數據塊 。讀取到的數據塊是經過壓縮的,需要使用相應的解壓縮算法進行解壓縮,還原出原始數據 。在讀取數據時,還會根據 CRC32 校驗和對數據進行校驗,確保數據的完整性和準確性 。如果校驗失敗,說明數據可能在存儲或傳輸過程中出現了錯誤,會采取相應的處理措施,如重新讀取數據或返回錯誤信息 。
- 查詢算法優化:為了進一步提高查詢性能,InfluxDB 還采用了一些查詢算法優化策略。例如,謂詞下推(Predicate Pushdown)技術,它會將查詢條件盡可能地提前應用到數據讀取階段,只讀取滿足查詢條件的數據,減少不必要的數據傳輸和處理 。在查詢某個時間段內溫度大于某個閾值的數據時,謂詞下推技術會在讀取 TSM 文件數據塊時,就過濾掉不符合溫度閾值條件的數據,只返回滿足條件的數據,大大提高了查詢效率 。此外,InfluxDB 還支持向量化執行(Vectorized Execution),它將數據按列進行批量處理,利用現代 CPU 的 SIMD(Single Instruction Multiple Data)指令集,一次處理多個數據元素,進一步加速查詢操作 。在進行聚合計算時,向量化執行可以同時對多個數據點進行計算,減少了指令執行次數和數據訪問次數,提高了計算效率 。
三、InfluxDB 空間回收大揭秘
(一)空間回收的重要性
在 InfluxDB 的實際應用中,隨著數據不斷寫入和刪除,磁盤空間的管理變得至關重要。如果不能及時回收被刪除數據所占用的空間,磁盤空間會逐漸被填滿,不僅會影響系統的正常運行,還可能導致數據寫入失敗或查詢性能急劇下降 。在一個實時監控大量服務器的場景中,每天會產生海量的監控數據,同時也會根據數據保留策略刪除舊數據。若空間回收不及時,磁盤空間很快就會被占滿,新的監控數據無法寫入,服務器的實時狀態無法被準確監測,運維人員也就無法及時發現和解決服務器可能出現的問題 。此外,合理的空間回收還能提高存儲資源的利用率,降低存儲成本,讓有限的存儲資源發揮更大的價值 。通過及時回收空間,可以將釋放出來的空間用于存儲更有價值的數據,避免了因存儲不足而需要購買額外存儲設備的成本支出 。
(二)數據刪除與墓碑文件
在 InfluxDB 中,當執行數據刪除操作時,并不會立即將數據從磁盤上的 TSM 文件中物理刪除 。這是因為直接物理刪除數據會涉及到復雜的文件操作和數據重排,會嚴重影響系統的性能和穩定性 。InfluxDB 采用了一種更為高效的方式,即生成墓碑文件(Tombstone File) 。當用戶執行刪除操作時,InfluxDB 會在 WAL 中寫入刪除條目,并更新內存中的索引,標記相應的數據為已刪除 。同時,會為包含這些被刪除數據的 TSM 文件生成一個墓碑文件 。墓碑文件就像是一個特殊的 “標記”,它記錄了被刪除數據在 TSM 文件中的位置和范圍等信息 。在 InfluxDB 啟動時,會讀取墓碑文件,忽略掉被標記為刪除的數據塊,從而避免讀取這些無效數據 。在進行數據合并(Compaction)操作時,墓碑文件中的信息會被用來移除已刪除的數據,真正釋放磁盤空間 。例如,在一個存儲傳感器歷史數據的 InfluxDB 數據庫中,當刪除某段時間內的傳感器數據時,并不會立即清空 TSM 文件中的這些數據,而是生成墓碑文件標記它們 。這樣在后續的查詢中,系統會自動跳過這些被標記的數據,而在數據合并時,這些被標記的數據會被徹底移除,實現空間回收 。
(三)壓縮與合并:釋放空間的關鍵
InfluxDB 通過壓縮和合并 TSM 文件來回收空間,這是其空間回收機制的核心環節 。
- 壓縮算法的選擇:InfluxDB 采用了專門針對時間序列數據設計的壓縮算法,如 Gorilla 壓縮算法 。這種算法充分利用了時間序列數據的特點,即數據在時間上具有連續性和相關性,相鄰數據點之間的變化通常較小 。Gorilla 算法通過對整數和浮點數進行編碼,能夠實現高壓縮比,有效減少數據存儲所需的磁盤空間 。在存儲大量傳感器采集的溫度數據時,由于溫度變化相對平穩,Gorilla 算法可以將這些數據壓縮到很小的體積,大大節省了存儲空間 。同時,這種算法在讀取數據時的解壓速度也非常快,能夠滿足實時查詢對數據讀取速度的要求 ,確保系統能夠快速響應查詢請求,將解壓后的數據及時返回給用戶 。
- 合并策略:InfluxDB 會定期對 TSM 文件進行合并操作 。當系統中存在多個小的 TSM 文件時,合并操作會將這些小文件合并成一個大的 TSM 文件 。在合并過程中,會對數據進行重新組織和優化,移除墓碑文件標記的已刪除數據,從而實現空間的回收 。合并操作還能減少文件數量,降低文件系統的管理開銷,提高查詢性能 。因為在查詢數據時,需要遍歷的文件數量減少了,數據定位和讀取的速度也就更快了 。例如,在每天夜間系統負載較低時,InfluxDB 會自動觸發 TSM 文件的合并操作,將當天生成的多個小 TSM 文件合并成一個或幾個大的 TSM 文件,在釋放磁盤空間的同時,也為第二天的數據寫入和查詢做好了準備 。