阿里雲分布式快取OCS與DB之間的資料一致性

2022-09-15 06:39:10 字數 3912 閱讀 9838

【分布式系統的資料一致性問題】

ocs概要介紹

ocs是阿里巴巴集團的分布式快取產品,支撐著**、阿里巴巴、支付寶的日常運作,尤其在雙11等大型活動上,承載了絕大多數的資料請求。與ocs相比,著名的memcached具備了分布式集群管理的功能。2023年ocs經歷了從分布式到雲服務的進化,作為阿里雲服務的快取產品正式商業化。

ocs技術講解

ocs的核心儲存是**的開源產品tair(發音:太愛兒)

tair原理

角色上分為dataserver,configserver:

configserver負責資料的路由表管理,決定著哪些資料應該去**訪問。同時也管理著dataserver節點的存活狀態,自動踢出宕機或者異常節點。

dataserver是資料儲存節點,負責資料的增刪改查。通過plugin機制支援多種儲存引擎。常用的有基於記憶體的,所有的資料儲存在記憶體之中,查詢速度快,但不持久化,網路正常的情況下,客戶端在0.2ms內得到請求響應。另外一種常用儲存引擎基於ssd介質再依靠記憶體加速,特點是容量大,成本低,效能上接近記憶體引擎,客戶端請求響應時間大概是1ms。

集群初始化時configserver會根據dataserver的數量分配bucketid到dataserver上,這層對映關係就是資料路由索引,bucketid屬於[0-1023]的範圍內。客戶端第一次啟動時會從configserver上拉取對映關係,之後的讀寫請求,根據全域性約定的hash演算法(例如murmurhash(key)24)計算出bucketid,根據對映關係描述向指定的dataserver上傳送請求。

configserver上的路由資訊會根據dataserver存活狀況動態修改更新;新結果再告知給dataserver;當dataserver處理客戶端響應時,將變更通知給客戶端。

圖1 路由路徑

從tair到ocs

雲服務化的過程中,首要問題是滿足使用者的相容性需求,使用者訪問介面上支援廣泛流行的memcached介面,原生於memcached的應用,可以無縫遷移到ocs上來。

其次是穩定性,集群公升級時,由於程序重啟會造成應用請求ocs瞬間報錯,ocs實現了一套熱公升級方案,在保持tcp鏈結不中斷的情況下重啟程序。

雲服務還有乙個重要特性就是多租戶,多租戶的情況下,為了防止某一兩個使用者的高併發訪問造成集群負載上公升,從而影響了其他租戶的穩定性。ocs內部對不同的租戶進行了資源隔離,針對請求量、頻寬、記憶體使用量做了嚴格的限制。不同規格的使用者可以購買不同規格的ocs例項,之間不會互相干擾。

與ocs相比,自建的memcached解決了單機容量上線問題,實現擴容自動化且不需要修改客戶端配置,同時輸出了效能監控指標,網頁版console命令等。

快取失效一致性問題

一般快取的使用方式是:先讀取快取,若不存在則從db中讀取,並將結果寫入到快取中;下次資料讀取時便可以直接從快取中獲取資料。

資料的修改是直接失效快取資料,再修改db內容,避免db修改成功,但由於網路或者其他問題導致快取資料沒有清理,造成了髒資料。

但這樣仍然無法避免髒資料的產生,一種併發的場景下:假設業務對資料key:hello value:world有大量的讀取和修改請求。執行緒a向ocs讀取key:hello,得到not found結果,開始向db請求資料,得到資料key:hello value:world;接下來準備向ocs寫入此條資料,但在寫入ocs前(網路,cpu都等可能導致a執行緒處理速度降低)另一b執行緒請求修改資料key:hello value:ocs,首先執行失效快取動作(因為b執行緒並不知道是否有此條資料,因此直接執行失效操作),ocs成功處理了失效請求。轉回到a執行緒繼續執行寫入ocs,將key:hello value:world寫入到快取中,a執行緒任務結束;b執行緒也成功修改了db資料內容為key:hello value:ocs。

圖2 併發時序

此時ocs中的資料為key:hello value:world;db中的資料為key:hello value:ocs,出現快取髒資料!

為了解決這個問題,ocs擴充了memcached協議(公有雲即將支援),增加了deleteandincversion介面。此介面並不會真的刪除資料,而是給資料打了標籤,表明已失效狀態,並且增加資料版本號;如果資料不存在則寫入null,同時也生成隨機資料版本號。ocs寫入支援原子對比版本號:假設傳入的版本號與ocs儲存的資料版本號一致或者原資料不存在,則准許寫入,否則拒絕修改。

回到剛才的場景上:執行緒a向ocs讀取key:hello,得到not found結果,開始向db請求資料,得到資料key:hello value:world;接下來準備向ocs寫入此條資料,版本號資訊預設為1;在a寫入ocs前另乙個b執行緒發起了動作修改資料key:hello value:ocs,首先執行刪除快取動作,ocs順利處理了deleteandincversion請求,生成了隨機版本號12345(約定大於1000)。轉回到a執行緒繼續執行寫入ocs,請求將key:hello value:world寫入,此時快取系統發現傳入的版本號資訊不匹配(1 != 12345),寫入失敗,a執行緒任務結束;b執行緒也成功修改了db資料內容為key:hello value:ocs。

此時ocs中的資料為key:hello value:null version:12345;db中的資料為key:hello value:ocs,後續讀任務時會再次嘗試將db中的資料寫入到ocs中。

類似的併發場景還有很多,讀者可以自行推演,同時也可以思考下為何約定隨機生成的版本要大於1000?

快取資料的同步的一致性問題

隨著**規模增長和可靠性的提公升,會面臨多idc的部署,每個idc都有一套獨立的db和快取系統,這時快取一致性又成了突出的問題。

首先快取系統為了保證高效率,會杜絕磁碟io,哪怕是寫binlog;當然快取系統為了效能可以只同步刪除,不同步寫入,那麼快取的同步一般會優先於db同步到達(畢竟快取系統的效率要高得多),那麼就會出現快取中無資料,db中是舊資料的場景。此時,有業務請求資料,讀取快取not found,從db讀取並載入到快取中的仍然是舊資料,db資料同步到達時也只更新了db,快取髒資料無法被清除。

圖3 併發時序

從上面的情況可以看出,不一致的根本原因是異構系統之間無法協同同步,不能保證db資料先同步,快取資料後同步。所以就要考慮快取系統如何等待db同步,或者能否做到兩者共用一套同步機制?快取同步也依賴db binlog是乙個可行的方案。

idc1中的db,通過binlog同步給idc2中的db,此時idc2-db資料修改也會產生自身的binlog,快取的資料同步就可以通過idc2-db binlog進行。快取同步模組分析binlog後,失效相應的快取key,同步從並行改為序列,保證了先後順序

這樣,idc間的資料同步架構更加簡單清晰,系統服用率高,做好binlog同步和抓取即可。

圖4 異地同步

總結

不同系統之間的資料同步一直是乙個世界性的問題,目前仍然沒有方法解除cap魔咒,只能根據實際的情況在三者之間尋找理想的平衡點。本文介紹的解決方案,其一是利用了快取系統的原子操作,其二是利用了外部系統同步機制保證先後,都是在犧牲最小的效能代價時獲取最大的一致性保證,但仍然無法覆蓋全部場景下的一致性問題。

本地快取與分布式快取

因為系統已經無法從優化業務 的角度去優化系統了 為了提高系統的效能 可以將對資料一直性不高和不會頻繁修改的資料存入快取中 避免頻繁訪問資料庫 以此來優化效能 首先去快取中查詢如果沒有再從資料庫中查詢並儲存至快取中 如果有直接返回 可以在專案中新建乙個map用雲儲存快取資料 快取使用流程和之前一樣 有...

伏羲 阿里雲分布式排程系統

今天,大資料已經從概念發展到在很多行業落地生根。廣泛用在電商 金融 企業等行業,幫助行業分析資料 挖掘資料的價值。即使在傳統的醫療 安全 交通等領域也越來越多的應用大資料的技術。資料 價值二者之間的聯絡是計算,計算是大資料中最核心的部分。大資料計算就是將原來一台臺的伺服器通過網路連線起來成為乙個整體...

阿里雲centoshadoop偽分布式環境搭建

本人不才,在雲伺服器上搭建hadoop 偽分布式時遇到很多問題,找了很多資料,問了很多人,都失望而歸,最後自己折騰成功了。首先配置問題,可以參看hadoop官網,就不多說了。其次最重要的是伺服器的位址對映問題,1.主機名稱必須和core site.xml中的hdfs 9000相同.2.ect hos...