|
分布式緩存一般被定義為一個數(shù)據(jù)集合,它將數(shù)據(jù)分布(或分區(qū))于任意數(shù)目的集群節(jié)點上。集群中的一個具體節(jié)點負責(zé)緩存中的一部分數(shù)據(jù),整體對外提供統(tǒng)一的訪問接口 [1]。分布式緩存一般基于冗余備份機制實現(xiàn)數(shù)據(jù)高可用,又被稱為內(nèi)存數(shù)據(jù)網(wǎng)格(IMDG, in-memory data grid)。在云平臺飛速發(fā)展的今天,作為提升應(yīng)用性能的重要手段,分布式緩存技術(shù)在工業(yè)界得到了越來越廣泛的關(guān)注和研發(fā)投入 [2]。彈性緩存平臺 [3] 是分布式緩存集群在云計算場景下的新形態(tài),其強調(diào)集群的動態(tài)擴展性與高可用性。動態(tài)擴展性表達了緩存平臺可提供透明的服務(wù)擴展的能力,高可用性則表達了緩存平臺可以容忍節(jié)點失效。 Tair 是阿里巴巴集團自研的彈性緩存 / 存儲平臺,在內(nèi)部有著大量的部署和使用。Tair 的核心組件是一個高性能、可擴展、高可靠的 NoSQL 存儲系統(tǒng)。目前支持 MDB、LDB、RDB 等存儲引擎。其中 MDB 是類似 Memcached 的內(nèi)存存儲引擎,LDB 是使用 LSM Tree 的持久化磁盤 KV 存儲引擎,RDB 是支持 Queue、Set、Maps 等數(shù)據(jù)結(jié)構(gòu)的內(nèi)存及持久化存儲引擎。 Tair 的數(shù)據(jù)分片和路由算法采用了 Amazon 于 2007 年提出的一種改進的一致性哈希算法 [4]。該算法將整個哈??臻g分為若干等大小的 Q 份數(shù)據(jù)分區(qū)(也稱為虛擬節(jié)點,Q>>N,N 為緩存節(jié)點數(shù)),每個緩存節(jié)點依據(jù)其處理能力分配不同數(shù)量的數(shù)據(jù)分區(qū)??蛻舳苏埱蟮臄?shù)據(jù) Key 值經(jīng)哈希函數(shù)映射至哈希環(huán)上的位置記為 token,token 值再次被哈希映射為某一分區(qū)標識。得到分區(qū)標識后,客戶端從分區(qū)服務(wù)器映射表中查詢存放該數(shù)據(jù)分區(qū)的緩存節(jié)點后進行數(shù)據(jù)訪問。使用該算法對相同數(shù)據(jù) Key 進行計算,其必然會被映射到固定的 DataServer 上,如圖: 此時 DataServer 單節(jié)點的讀寫性能便成了單數(shù)據(jù) Key 的讀寫性能瓶頸,且無法通過水平擴展節(jié)點的方式來解決。由于阿里巴巴集團內(nèi)部電商系的促銷活動天然的存在熱點數(shù)據(jù),所以要增強整個彈性緩存 / 存儲平臺的穩(wěn)定性和服務(wù)能力,就必須提升熱點數(shù)據(jù)的讀寫能力,使其能做到水平擴展。 本文基于 Tair 的存儲和訪問原理,對緩存的讀寫熱點問題進行討論,并給出一個滿足現(xiàn)階段需求的熱點數(shù)據(jù)讀寫問題的解決方案。 解決方案分為三部分:熱點識別、讀熱點方案和寫熱點方案。其中讀寫熱點方案都是以服務(wù)端能對熱點訪問進行精準的識別為前提的。另外對于可以提前預(yù)知熱點 Key 的情況,也提供相應(yīng)的客戶端 API 以支持特定數(shù)據(jù) Key 或者特定 Namespace 的所有數(shù)據(jù) Key 預(yù)先標記為熱點 Key 的能力。 DataServer 收到客戶端的請求后,由每個具體處理請求的工作線程(Worker Thread)進行請求的統(tǒng)計。工作線程用來統(tǒng)計熱點的數(shù)據(jù)結(jié)構(gòu)均為 ThreadLocal 模式的數(shù)據(jù)結(jié)構(gòu),完全無鎖化設(shè)計。熱點識別算法使用精心設(shè)計的多級加權(quán) LRU 鏈和 HashMap 組合的數(shù)據(jù)結(jié)構(gòu),在保證服務(wù)端請求處理效率的前提下進行請求的全統(tǒng)計,支持 QPS 熱點和流量熱點(即請求的 QPS 不大但是數(shù)據(jù)本身過大而造成的大流量所形成的熱點)的精準識別。每個采樣周期結(jié)束時,工作線程會將統(tǒng)計的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)交到后臺的統(tǒng)計線程池進行分析處理。統(tǒng)計工作異步在后臺進行,不搶占正常的數(shù)據(jù)請求的處理資源。 原始 Tair 的數(shù)據(jù)訪問方式是先進行 Hash(Key)%BucketCount 的計算,得出具體的數(shù)據(jù)存儲 Bucket,再檢索數(shù)據(jù)路由表找到該 Bucket 所在的 DataServer 后對其進行讀寫請求的。所以相同 Key 的讀寫請求必然落在固定的 DataServer 上,且無法通過水平擴展 DataServer 數(shù)量來解決。 本方案通過在 DataServer 上劃分一塊 HotZone 存儲區(qū)域的方式來解決熱點數(shù)據(jù)的訪問。該區(qū)域存儲當(dāng)前產(chǎn)生的所有讀熱點的數(shù)據(jù),由客戶端配置的緩存訪問邏輯來處理各級緩存的訪問。多級緩存架構(gòu)如下: 所有 DataServer 的 HotZone 存儲區(qū)域之間沒有權(quán)重關(guān)系,每個 HotZone 都存儲相同的讀熱點數(shù)據(jù)??蛻舳藢狳c數(shù)據(jù) Key 的請求會隨機到任意一臺 DataServer 的 HotZone 區(qū)域,這樣單點的熱點請求就被散列到多個節(jié)點乃至整個集群。 客戶端邏輯 當(dāng)客戶端在第一次請求前初始化時,會獲取整個 Tair 集群的節(jié)點信息以及完整的數(shù)據(jù)路由表,同時也會獲取配置的熱點散列機器數(shù)(即客戶端訪問的 HotZone 的節(jié)點范圍)。隨后客戶端隨機選擇一個 HotZone 區(qū)域作為自身固定的讀寫 HotZone 區(qū)域。在 DataServer 數(shù)量和散列機器數(shù)配置未發(fā)生變化的情況下,不會改變選擇。即每個客戶端只訪問唯一的 HotZone 區(qū)域。 客戶端收到服務(wù)端反饋的熱點 Key 信息后,至少在客戶端生效 N 秒。在熱點 Key 生效期間,當(dāng)客戶端訪問到該 Key 時,熱點的數(shù)據(jù)會首先嘗試從 HotZone 節(jié)點進行訪問,此時 HotZone 節(jié)點和源數(shù)據(jù) DataServer 節(jié)點形成一個二級的 Cache 模型。客戶端內(nèi)部包含了兩級 Cache 的處理邏輯,即對于熱點數(shù)據(jù),客戶端首先請求 HotZone 節(jié)點,如果數(shù)據(jù)不存在,則繼續(xù)請求源數(shù)據(jù)節(jié)點,獲取數(shù)據(jù)后異步將數(shù)據(jù)存儲到 HotZone 節(jié)點里。使用 Tair 客戶端的應(yīng)用常規(guī)調(diào)用獲取數(shù)據(jù)的接口即可,整個熱點的反饋、識別以及對多級緩存的訪問對外部完全透明。HotZone 緩存數(shù)據(jù)的一致性由客戶端初始化時設(shè)置的過期時間來保證,具體的時間由具體業(yè)務(wù)對緩存數(shù)據(jù)不一致的最大容忍時間來決定。 客戶端存儲于本地的熱點反饋過期后,數(shù)據(jù) Key 會到源 DataServer 節(jié)點讀取。如果該 Key 依舊在服務(wù)端處于熱點狀態(tài),客戶端會再次收到熱點反饋包。因為所有客戶端存儲于本地的熱點反饋信息的失效節(jié)奏不同,所以不會出現(xiàn)同一瞬間所有的請求都回源的情況。即使所有請求回源,也僅需要回源讀取一次即可,最大的讀取次數(shù)僅為應(yīng)用機器數(shù)。若回源后發(fā)現(xiàn)該 Key 已不是熱點,客戶端便回到常規(guī)的訪問模式。 散列比和 QPS 偏差的關(guān)系 處理方式 對于寫熱點,因為一致性的問題,難以使用多級緩存的方式來解決。如果采用寫本地 Cache,再異步更新源 DataServer 的方案。那么在 Cache 寫入但尚未更新的時候,如果業(yè)務(wù)機器宕機,就會有已寫數(shù)據(jù)丟失的問題。同時,本地 Cache 會導(dǎo)致進行數(shù)據(jù)更新的某應(yīng)用機器當(dāng)前更新周期內(nèi)的修改對其他應(yīng)用機器不可見,從而延長數(shù)據(jù)不一致的時間。故多級 Cache 的方案無法支持寫熱點。最終寫熱點采用在服務(wù)端進行請求合并的方式進行處理。 熱點 Key 的寫請求在 IO 線程被分發(fā)到專門的熱點合并線程處理,該線程根據(jù) Key 對寫請求進行一定時間內(nèi)的合并,隨后由定時線程按照預(yù)設(shè)的合并周期將合并后的請求提交到引擎層。合并過程中請求結(jié)果暫時不返回給客戶端,等請求合并寫入引擎成功后統(tǒng)一返回。這樣做不會有一致性的問題,不會出現(xiàn)寫成功后卻讀到舊數(shù)據(jù),也避免了 LDB 集群返回成功,數(shù)據(jù)并未落盤的情況(假寫)。具體的合并周期在服務(wù)端可配置,并支持動態(tài)修改生效。 客戶端設(shè)計 寫熱點的方案對客戶端完全透明,不需要客戶端做任何修改。 性能指標 LDB 集群實際壓測效果為單 Key 合并能做到單 Key 百萬的 QPS(1ms 合并,不限制合并次數(shù)),線上實際集群為了盡可能保證實時性,均采用了最大 0.1ms 以及單次最大合并次數(shù)為 100 次的限制。這樣單 Key 在引擎層的最大落盤 QPS 就能控制在 10000 以下(而合并的 QPS 則取決于應(yīng)用的訪問頻率)。Tair 服務(wù)端的包處理是完全異步化的,進行熱點請求的合并操作并不阻塞對其他請求的處理。唯一的影響就是增大客戶端對熱點 key 的寫請求的 RT. 按照現(xiàn)在的配置,最壞情況下,客戶端的熱點 key 的寫操作會增大 0.1ms,這個影響是微乎其微的。
|
|
|