阿里巴巴分布式快取服務Tair的熱點資料雜湊機制

2021-09-10 10:25:59 字數 3719 閱讀 5142

作者丨劉歡(淺奕)

分布式快取一般被定義為乙個資料集合,它將資料分布(或分割槽)於任意數目的集群節點上。集群中的乙個具體節點負責快取中的一部分資料,整體對外提供統一的訪問介面 [1]。分布式快取一般基於冗餘備份機制實現資料高可用,又被稱為記憶體資料網格(imdg, in-memory data grid)。在雲平台飛速發展的今天,作為提公升應用效能的重要手段,分布式快取技術在工業界得到了越來越廣泛的關注和研發投入 [2]。彈性快取平台 [3] 是分布式快取集群在雲計算場景下的新形態,其強調集群的動態擴充套件性與高可用性。動態擴充套件性表達了快取平台可提供透明的服務擴充套件的能力,高可用性則表達了快取平台可以容忍節點失效。

tair 是阿里巴巴集團自研的彈性快取 / 儲存平台,在內部有著大量的部署和使用。tair 的核心元件是乙個高效能、可擴充套件、高可靠的 nosql 儲存系統。目前支援 mdb、ldb、rdb 等儲存引擎。其中 mdb 是類似 memcached 的記憶體儲存引擎,ldb 是使用 lsm tree 的持久化磁碟 kv 儲存引擎,rdb 是支援 queue、set、maps 等資料結構的記憶體及持久化儲存引擎。

tair 的資料分片和路由演算法採用了 amazon 於 2007 年提出的一種改進的一致性雜湊演算法 [4]。該演算法將整個雜湊空間分為若干等大小的 q 份資料分割槽(也稱為虛擬節點,q>>n,n 為快取節點數),每個快取節點依據其處理能力分配不同數量的資料分割槽。客戶端請求的資料 key 值經雜湊函式對映至雜湊環上的位置記為 token,token 值再次被雜湊對映為某一分割槽標識。得到分割槽標識後,客戶端從分割槽伺服器對映表中查詢存放該資料分割槽的快取節點後進行資料訪問。使用該演算法對相同資料 key 進行計算,其必然會被對映到固定的 dataserver 上,如圖:

本文基於 tair 的儲存和訪問原理,對快取的讀寫熱點問題進行討論,並給出乙個滿足現階段需求的熱點資料讀寫問題的解決方案。

解決方案

解決方案分為三部分:熱點識別、讀熱點方案和寫熱點方案。其中讀寫熱點方案都是以服務端能對熱點訪問進行精準的識別為前提的。另外對於可以提前預知熱點 key 的情況,也提供相應的客戶端 api 以支援特定資料 key 或者特定 namespace 的所有資料 key 預先標記為熱點 key 的能力。

dataserver 上的熱點統計過程

dataserver 收到客戶端的請求後,由每個具體處理請求的工作執行緒(worker thread)進行請求的統計。工作執行緒用來統計熱點的資料結構均為 threadlocal 模式的資料結構,完全無鎖化設計。熱點識別演算法使用精心設計的多級加權 lru 鏈和 hashmap 組合的資料結構,在保證服務端請求處理效率的前提下進行請求的全統計,支援 qps 熱點和流量熱點(即請求的 qps 不大但是資料本身過大而造成的大流量所形成的熱點)的精準識別。每個取樣週期結束時,工作執行緒會將統計的資料結構轉交到後台的統計執行緒池進行分析處理。統計工作非同步在後台進行,不搶占正常的資料請求的處理資源。

讀熱點方案

服務端設計

原始 tair 的資料訪問方式是先進行 hash(key)%bucketcount 的計算,得出具體的資料儲存 bucket,再檢索資料路由表找到該 bucket 所在的 dataserver 後對其進行讀寫請求的。所以相同 key 的讀寫請求必然落在固定的 dataserver 上,且無法通過水平擴充套件 dataserver 數量來解決。

本方案通過在 dataserver 上劃分一塊 hotzone 儲存區域的方式來解決熱點資料的訪問。該區域儲存當前產生的所有讀熱點的資料,由客戶端配置的快取訪問邏輯來處理各級快取的訪問。多級快取架構如下:

客戶端設計

客戶端邏輯

當客戶端在第一次請求前初始化時,會獲取整個 tair 集群的節點資訊以及完整的資料路由表,同時也會獲取配置的熱點雜湊機器數(即客戶端訪問的 hotzone 的節點範圍)。隨後客戶端隨機選擇乙個 hotzone 區域作為自身固定的讀寫 hotzone 區域。在 dataserver 數量和雜湊機器數配置未發生變化的情況下,不會改變選擇。即每個客戶端只訪問唯一的 hotzone 區域。

客戶端收到服務端反饋的熱點 key 資訊後,至少在客戶端生效 n 秒。在熱點 key 生效期間,當客戶端訪問到該 key 時,熱點的資料會首先嘗試從 hotzone 節點進行訪問,此時 hotzone 節點和源資料 dataserver 節點形成乙個二級的 cache 模型。客戶端內部包含了兩級 cache 的處理邏輯,即對於熱點資料,客戶端首先請求 hotzone 節點,如果資料不存在,則繼續請求源資料節點,獲取資料後非同步將資料儲存到 hotzone 節點裡。使用 tair 客戶端的應用常規呼叫獲取資料的介面即可,整個熱點的反饋、識別以及對多級快取的訪問對外部完全透明。hotzone 快取資料的一致性由客戶端初始化時設定的過期時間來保證,具體的時間由具體業務對快取資料不一致的最大容忍時間來決定。

客戶端儲存於本地的熱點反饋過期後,資料 key 會到源 dataserver 節點讀取。如果該 key 依舊在服務端處於熱點狀態,客戶端會再次收到熱點反饋包。因為所有客戶端儲存於本地的熱點反饋資訊的失效節奏不同,所以不會出現同一瞬間所有的請求都回源的情況。即使所有請求回源,也僅需要回源讀取一次即可,最大的讀取次數僅為應用機器數。若回源後發現該 key 已不是熱點,客戶端便回到常規的訪問模式。

雜湊比和 qps 偏差的關係

服務端設計

處理方式

對於寫熱點,因為一致性的問題,難以使用多級快取的方式來解決。如果採用寫本地 cache,再非同步更新源 dataserver 的方案。那麼在 cache 寫入但尚未更新的時候,如果業務機器宕機,就會有已寫資料丟失的問題。同時,本地 cache 會導致進行資料更新的某應用機器當前更新週期內的修改對其他應用機器不可見,從而延長資料不一致的時間。故多級 cache 的方案無法支援寫熱點。最終寫熱點採用在服務端進行請求合併的方式進行處理。

熱點 key 的寫請求在 io 執行緒被分發到專門的熱點合併執行緒處理,該執行緒根據 key 對寫請求進行一定時間內的合併,隨後由定時執行緒按照預設的合併週期將合併後的請求提交到引擎層。合併過程中請求結果暫時不返回給客戶端,等請求合併寫入引擎成功後統一返回。這樣做不會有一致性的問題,不會出現寫成功後卻讀到舊資料,也避免了 ldb 集群返回成功,資料並未落盤的情況(假寫)。具體的合併週期在服務端可配置,並支援動態修改生效。

客戶端設計

寫熱點的方案對客戶端完全透明,不需要客戶端做任何修改。

效能指標

ldb 集群實際壓測效果為單 key 合併能做到單 key 百萬的 qps(1ms 合併,不限制合併次數),線上實際集群為了盡可能保證實時性,均採用了最大 0.1ms 以及單次最大合併次數為 100 次的限制。這樣單 key 在引擎層的最大落盤 qps 就能控制在 10000 以下(而合併的 qps 則取決於應用的訪問頻率)。tair 服務端的包處理是完全非同步化的,進行熱點請求的合併操作並不阻塞對其他請求的處理。唯一的影響就是增大客戶端對熱點 key 的寫請求的 rt. 按照現在的配置,最壞情況下,客戶端的熱點 key 的寫操作會增大 0.1ms,這個影響是微乎其微的。

參考文獻

Tair分布式快取

redis很好用,提供快取服務。相比memcached多了新資料結構和主從模式增加可用性。不過redis有一點不能滿足一些網際網路公司開發者需求。redis集群中,想用快取必須得指明redis伺服器位址去要。這就增加了程式的維護複雜度。因為redis伺服器很可能是需要頻繁變動的。為什麼不能像操作分布...

阿里巴巴分布式事務利器Seata環境準備

阿里巴巴自從跟springcloud共同發起建立微服務開源社群時,在生態內提供了一款適用於分布式應用程式 dubbo springcloud 的事務框架seata,該框架經過多個大版本的發布,已經支援mysql oracle這兩種資料庫事務回滾 rollback 以及提交 commit 控制,每次發...

分布式快取

分布式快取 原則來說跟應用伺服器分布式應該是一樣,但快取是有狀態的。怎麼樣提高命中?1.最原始的演算法 那就是key hash取模,取到伺服器ip。在大量伺服器伸縮行有問題,加入一台伺服器就有可能讓所有的快取都失效。如 key hash 後是100,取10膜是0,取11膜 1,101 取10膜是1,...