TiKV + SPDK,探索存儲的性能極限

近日,由 TiDB 社區主辦,專屬於全球開發者與技術愛好者的頂級挑戰賽事——TiDB Hackathon 2020 比賽圓滿落幕。今年是 TiDB Hackathon 第四次舉辦,參賽隊伍規模創歷屆之最,共有 45 支來自全球各地的隊伍報名,首次實現全球聯動。經過 2 天時間的極限挑戰, 大賽湧現出不少令人激動的項目。

本篇文章的作者爲 ️ ️隊的楊可奧,他們團隊在本次 Hackathon 比賽中嘗試使用 SPDK 提供的工具讓 TiKV 基於用戶態存儲運行,並獲得了顯著的性能提升。

現代軟件的結構建立在一層一層抽象之上,在大部分時候,這樣的“抽象”意味着對調度細節的隱藏和對性能的損耗。應用不制定查詢計劃,而將制定查詢計劃的任務交給數據庫;數據庫不直接寫入磁盤,而由操作系統來決定寫入的時機和量;操作系統也不會直接在磁片 / 顆粒上操作,而是批量發送指令再由磁盤的控制器來決定執行的方案。在大部分時候,這些調度交由知識更加豐富的一方來進行決策,所以表現地也還不錯;而隱含於其中的性能損耗(比如使用系統調用時的額外開銷)對性能不敏感的應用來說也無關緊要。

可惜的是,數據庫恰巧是個反例 ——在這篇文章中,將會講述現代儲存結構中一系列抽象的弊端,以及本次 Hackathon 期間 ️ ️隊通過在 TiKV 中引入 SPDK 工具來克服這些問題的努力。

問題背景

對於數據庫而言,直接可用的存儲抽象是從文件系統開始的,通過創建文件、對文件進行寫入和讀取來間接地讀寫硬盤。從應用發起相關的系統調用開始,直到數據落在磁盤、顆粒上,大致需要以下幾個步驟:

  1. 操作系統收到系統調用;
  2. 文件系統的抽象層(VFS),頁緩存等機制在此時發揮作用;
  3. 文件系統的具體實現;
  4. 對塊設備的讀寫,IO 調度器、設備映射(device mapper)等功能在此時發揮作用;
  5. 通過硬件驅動向存儲設備發送指令;
  6. 硬件內部的控制器處理這些指令,在磁盤、顆粒上進行操作。

這樣做直接帶來了幾個問題:

其一是系統調用具有不可忽視的開銷。對於 IO 操作這類複雜的系統調用,除了需要由用戶態切換入內核態之外,操作系統也需要進行進程狀態的保存和恢復。在存儲設備的性能大幅提升的今天,這二者的開銷佔據的比例也逐漸變得不可忽視。

其二是文件系統的實現對上層應用的影響巨大。因爲不同的文件系統使用不同的數據結構來管理文件、適用於不同的應用場景:比如 XFS 在大量小文件時表現不佳。這種影響對於上層應用來說是不可控的。

其三是 Linux 作爲一個通用操作系統,在頁緩存算法的選取、對底層硬件的支持上都以“通用”爲第一要求,這使得它的設計無法對某類專門應用(比如數據庫)和某些特定硬件(比如 NVMe 磁盤)做出充分的優化。

其四是存在着重複日誌的問題。抽象的每一層都試圖通過日誌保證自身的穩定性:NVMe 控制器有日誌、文件系統也可能有日誌、RocksDB 也有日誌。在現在的情形下要保證整體的穩健是缺一不可的。但如果能全局考慮、整體分析,能否節省出一些呢?

面對這些問題,解決的方式是顯而易見的 ——將應用向下延伸,探得越深,需要自己做的事情就越多越複雜,而帶來的性能上的收益就越大。

技術實現

在這次實踐中,我們將 “下探” 到上述的步驟五 —— 即從 TiKV 直接向 NVMe 磁盤發送指令。正如前文所言,“下探” 到哪一步事實上是一個權衡。我們團隊認爲當前階段 NVMe 磁盤逐漸普及開來,並且提供了特別多相較於傳統技術的新特性(比如 4KB 原子寫、極低延遲和超高併發隊列),這使得針對 NVMe 設備進行設計變得更有必要。幸運的是,這種想法和社區環境是相符的:Intel 已經提供了開源的存儲工具包 SPDK,裏面包含了 NVMe 的用戶態驅動和對它的一些包裝。所謂用戶態驅動,便是通過 VFIO 等方式將硬件 IO 內存映射至用戶態可訪問的內存,從而達到由應用程序不經過操作系統直接訪問硬件的目的,這一技術更廣泛地應用在虛擬機程序上,讓虛擬機能夠直接訪問硬件(比如訪問顯卡或網卡)達到“穿透”的目的。在此之上,SPDK 還實現了一套名爲 BlobFS 的“文件系統”,提供類似 POSIX 文件系統的函數接口。以下是使用 SPDK BlobFS 進行 IO 操作的大致步驟:

  1. 應用程序調用 blobfs_create, blobfs_read 等函數;
  2. 從文件系統操作映射到對存儲設備的操作;
  3. 向 NVMe 設備發送指令(技術上講,是向 NVMe 設備對應的內存區域中寫入指令)。

相比起 Linux 功能全面、複雜的 IO 棧,使用 SPDK 之後的 IO 步驟顯得簡單不少。相比之下,使用 SPDK blobfs 能夠帶來以下顯著優勢:

  1. 函數調用的開銷遠小於系統調用。
  2. blobfs 利用了 NVMe 設備能夠進行原子讀寫的特性,簡化了文件系統元數據的管理。
  3. 擁有不同於通用 Page Cache 的緩存策略,對連續讀寫有較大優化。對於 Rocksdb 來說,這種緩存策略對 LSM 的 Compaction 優化較爲明顯。但同時也失去了對點查的額外緩存。

可以看出,這些優勢與上文提到的四個問題對應,消除了系統調用的開銷、使用了更適合數據庫程序和 NVMe 磁盤的數據結構與緩存算法、簡化了文件系統的日誌。在將 SPDK blobfs 集成至 TiKV 中之後,應該能夠獲得較大的性能提升。

結果分析

期待着獲得性能提升的嘗試最終總要跑一跑 Benchmark 來看看它是否能達到預期。因爲測試資源和時間有限,同時爲了單純地比較 IO 上的提升,我們選取了 ycsb workload-a 爲基準進行了測試。最終結果超出了我的預期:

圖中數據點的標籤爲客戶端線程數,可以看出在容忍相同的延遲的前提下,基於 SPDK 的 TiKV 能夠提供更高的 Ops 即更大的吞吐量。

可見的未來

單論該項目的未來發展,可能更多的取決於歷史的發展 —— NVMe 磁盤是否已經足夠普及?TiKV 是否到了一定要通過它來提升性能的地步?我個人是很看好的:NVMe 磁盤的應用無論在民用還是工業都是大勢所趨;而 TiKV 作爲一款優秀的數據庫產品,更高的性能也是它一貫地追求。並且現在 TiDB 的雲服務問世,提供雲服務對用戶來說能夠顯著降低 SPDK 的使用和配置門檻(是無感知的提升)。

而在方法論上,進行這一選題的方法也已經在業內開花結果多年:比如將“下探”的過程更進一步,在軟件中完成 NVMe 控制器的工作,既是現在的 Open Channel SSD 技術,已經有論文研究了 LSM tree 中 sst 只讀與 SSD 中塊只讀(複寫需要先擦除)的這一共性,以減少意料之外的擦除帶來的性能下降;也可以後退一步,向 Linux 塊設備抽象上讀寫,比如 Ceph 的 BlueFS,相比於直接的文件系統讀寫將擁有更高的性能,而比起 SPDK 這樣的方法能有更好的硬件兼容性和更低的風險。

這些技術都頗爲有趣,也許在將來其中的一個或多個會出現在 TiKV 中,成爲邁向更高存儲性能的基石。

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