攜程開源Redis多數據中心解決方案-XPipe
Redis在攜程內部得到了廣泛的使用,根據客戶端數據統計,整個攜程全部Redis的讀寫請求在每秒200W,其中寫請求約每秒10W,很多業務甚至會將Redis當成內存資料庫使用。
這樣,就對Redis多數據中心提出了很大的需求,一是為了提升可用性,解決數據中心DR(DisasterRecovery)問題;二是提升訪問性能,每個數據中心可以讀取當前數據中心的數據,無需跨機房讀數據。在這樣的需求下,XPipe應運而生 。
從實現的角度來說,XPipe主要需要解決三個方面的問題,一是數據複製,同時在複製的過程中保證數據的一致性;二是高可用,xpipe本身的高可用和Redis系統的高可用;三是如何在機房異常時,進行DR切換。
下文將會從這三個方面對問題進行詳細闡述。最後,將會對測試結果和系統在生產環境運行情況進行說明。
為了方便描述,後面的行文中用DC代表數據中心(Data Center)。
一、數據複製問題
多數據中心首先要解決的是數據複製問題,即數據如何從一個DC傳輸到另外一個DC,通常有如下方案:
客戶端雙寫
從客戶端的角度來解決問題,單個客戶端雙寫兩個DC的伺服器。初看沒有什麼問題。但是深入看下去,如果寫入一個IDC成功,另外一個IDC失敗,那數據可能會不一致,為了保證一致,可能需要先寫入一個隊列,然後再將隊列的數據發送到兩個IDC。 如果隊列是本地隊列,那當前伺服器掛掉,數據可能會丟失;如果隊列是遠程隊列,又給整體的方案帶來了很大的複雜度。
目前的應用一般都是集群部署,會有多個客戶端同時操作。在多個客戶端的前提下,又帶來了新的問題。比如兩個客戶端ClientA和ClientB:
ClientA: set key value1
ClientB: set key value2
由於兩個客戶端獨立操作,到達伺服器的順序不可控,所以可能會導致兩個DC的伺服器對於同一個key,value不一致,如下:
Server1: setkey value1; set key value2;
Server2: setkey value2; set key value1;
在Server1,最終值為value2,在Server2,最終值為value1。
伺服器代理
proxy模式解決了多客戶端寫可能會導致數據不一致的問題。proxy類似於一個client,和單個client雙寫的問題類似,需要一個數據隊列保數據一致性。為了提升系統的利用率,單個proxy往往需要代理多個Redis server,如果proxy出問題,會導致大面積的系統故障。這樣,就對系統的性能和可用性提出了極大的挑戰,帶來實現的複雜度。
此外,在特殊的情況下,仍然會可能帶來數據的不一致,比如value和時間相關,或者是隨機數,兩個Redis伺服器所在系統的不一致帶來了數據的不一致。
考慮到以上情況,為了解決複製問題,我們決定採用偽slave的方案,即實現Redis協議,偽裝成為Redis slave,讓Redis master推送數據至偽slave。這個偽slave,我們把它稱為keeper,如下圖所示:
有了keeper之後,多數據中心之間的數據傳輸,可以通過keeper進行。keeper將Redis日誌數據緩存到磁碟,這樣,可以緩存大量的日誌數據(Redis將數據緩存到內存ring buffer,容量有限),當數據中心之間的網路出現較長時間異常時仍然可以續傳日誌數據。Redis協議不可更改,而keeper之間的數據傳輸協議卻可以自定義。這樣就可以進行壓縮,以提升系統性能,節約傳輸成本;多個機房之間的數據傳輸往往需要通過公網進行,這樣數據的安全性變得極為重要,keeper之間的數據傳輸也可以加密,提升安全性。
二、高可用
任何系統都可能會掛掉,如果keeper掛掉,多數據中心之間的數據傳輸可能會中斷,為了解決這個問題,需要保證keeper的高可用。我們的方案中,keeper有主備兩個節點,備節點實時從主節點複製數據,當主節點掛掉後,備節點會被提升為主節點,代替主節點進行服務。
提升的操作需要通過第三方節點進行,我們把它稱之為MetaServer,主要負責keeper狀態的轉化以及機房內部元信息的存儲。同時MetaServer也要做到高可用:每個MetaServer負責特定的Redis集群,當有MetaServer節點掛掉時,其負責的Redis集群將由其它節點接替;如果整個集群中有新的節點接入,則會自動進行一次負載均衡,將部分集群移交到此新節點。
Redis也可能會掛,Redis本身提供哨兵(Sentinel)機制保證集群的高可用。但是在Redis4.0版本之前,提升新的master後,其它節點連到此節點後都會進行全量同步,全量同步時,slave會處於不可用狀態;master將會導出rdb,降低master的可用性;同時由於集群中有大量數據(RDB)傳輸,將會導致整體系統的不穩定。
截止當前文章書寫之時,4.0仍然沒有發布release版本,而且攜程內部使用的Redis版本為2.8.19,如果升到4.0,版本跨度太大,基於此,我們在Redis3.0.7的版本基礎上進行優化,實現了psync2.0協議,實現了增量同步。下面是Redis作者對協議的介紹:https://gist.github.com/antirez/ae068f95c0d084891305。
三、DR切換
DR切換分為兩種可能,一種是機房真的掛了或者出異常,需要進行切換,另外一種是機房仍然健康,但是由於演練、業務要求等原因仍然需要切換到另外的機房。XPipe處理機房切換的流程如下:
檢查是否可以進行DR切換
類似於2PC協議,首先進行prepare,保證流程能順利進行。
原主機房master禁止寫入
此步驟,保證在遷移的過程中,只有一個master,解決在遷移過程中可能存在的數據丟失情況。
提升新主機房master
其它機房向新主機房同步
當然了,即使做了檢查,也無法絕對保證整個遷移過程肯定能夠成功,為此,我們提供回滾和重試功能。回滾功能可以回滾到初始的狀態,重試功能可以在DBA人工介入的前提下,修復異常條件,繼續進行切換。
根據以上分析,XPipe系統的整體架構如下所示:
Console用來管理多機房的元信息數據,同時提供用戶界面,供用戶進行配置和DR切換等操作。Keeper負責緩存Redis操作日誌,並對跨機房傳輸進行壓縮、加密等處理。Meta Server管理單機房內的所有keeper狀態,並對異常狀態進行糾正。
四、測試數據
我們關注的重點在於增加keeper後,平均延時的增加。測試方式如下圖所示。從client發送數據至master,並且slave通過keyspacenotification的方式通知到client,整個測試延時時間為t1+t2+t3。
首先我們測試Redis master直接複製到slave的延時,為0.2ms。然後在master和slave之間增加一層keeper,整體延時增加0.1ms,到0.3ms。相較於多個DC之間幾毫秒,幾十毫秒的延時,增加一層keeper帶來的延時是完全沒問題的。
在攜程生產環境進行了測試,生產環境兩個機房之間的ping TTL約為0.61ms,經過跨數據中心的兩層keeper後,測試得到的平均延時約為0.8ms,延時99.9線為2ms。
綜上所述:XPipe主要解決Redis多數據中心數據同步以及DR切換問題,同時,由於XPipe增強後的Redis版本優化了psync協議,會極大的提升Redis集群的穩定性。
同時,整個系統已經開源,歡迎大家一起參與優化整個系統:
XPipe: https://github.com/ctripcorp/x-pipe
XRedis(在Redis3.0.7版本上進行增強的版本):
https://github.com/ctripcorp/redis【作者簡介】孟文超,攜程技術中心框架研發部高級經理。2016年加入攜程,目前主要負責Redis多數據中心項目XPipe。此前曾在大眾點評工作,任基礎架構部門通信團隊負責人。
沒看夠?更多來自攜程技術人的一手乾貨,歡迎搜索關注「攜程技術中心」微信公號哦~
推薦閱讀:
※基於 Ruby 實現的移動 App 自動化測試框架 (AppiumBooster)
※有哪些優秀的 C/C++ 開源代碼框架?這些框架的設計思路是怎樣的?
※MVC到底是設計模式還是一種框架?