分散式快取Redis Cluster在華泰證券的探索與實踐

老魚筆記發表於2018-07-02
本文選自《交易技術前沿》總第三十期文章(2018年3月)
作者:樊建 陳營 葛寶磊/華泰證券股份有限公司

摘要:Redis Cluster作為最熱門的開源分散式快取,在券商領域會有怎樣的應用場景?本文從華泰證券的應用現狀出發,介紹了Redis Cluster在華泰證券的大規模實踐經驗。

一、引言

Redis是一個開源(BSD許可)的記憶體Key-Value儲存系統,它可以用作資料庫、快取和訊息中介軟體。它支援多種型別的資料結構,如:字串、雜湊)、列表、集合、有序集合與範圍查詢等。 Redis內建了複製、LRU驅動事件、事務、磁碟持久化等特性,並通過Redis哨兵(主從模式)和自動分割槽(Redis Cluster模式)提供高可用性。

官方的Redis Cluster推出前,常見的Redis Cluster開源方案主要是Codis和Twemproxy,兩者均採用Proxy的方式實現分散式。通過引入Proxy層來遮蔽底層資料的分佈,可以簡化客戶端的實現,但使得叢集架構變得複雜,維護成本上升。Redis從3.0開始支援自動分割槽,採用無中心節點方式實現Cluster模式。訪問Redis Cluster時,無需Proxy代理,具備Smart特性的客戶端直接與Redis Cluster中的每個節點連線。

Redis引入Cluster模式帶來的優勢在於:

1.可靠性:具有分割槽機制、副本機制和自動容錯機制;
2.高效能:保證了Redis高吞吐的前提下,可線性擴充套件到上千個節點;
3.可擴充套件性:基於分割槽的自動擴容、縮容,客戶端透明的資料遷移。

目前,Redis在網際網路、金融、傳統行業內的應用已十分廣泛。隨著金融業接入網際網路的業務增加,活動、促銷、節假日、熱門事件等可能帶來突發數倍甚至幾十倍的訪問峰值的情況時有發生,Redis Cluster是抵禦突發海量訪問的有效手段。

2. 基本原理及概念

Redis Cluster整體設計是比較簡單的,叢集架構採用無中心節點的方式實現,叢集中的節點通過Gossip協議相互交換叢集狀態。客戶端無需代理直接訪問服務端,客戶端通過Hash演算法計算出Key對應的雜湊槽,然後直接訪問雜湊槽對應的服務端節點。
Redis Cluster的拓撲結構如下圖所示:


圖1 Redis Cluster架構圖

叢集構建:

Redis Cluster提供了一組叢集搭建和管理命令,如:CLUSTER INFO、CLUSTER NODES、CLUSTER MEET等。實際使用過程中可以藉助命令列工具redis-trib.rb,可以方便的搭建一個叢集、平衡叢集雜湊槽分佈、刪除新增節點等。

搭建一個Redis Cluster僅需兩步:1.節點準備,將編譯好的Redis釋出到至少三臺伺服器上,修改配置檔案並啟動Redis節點;2.節點握手,使用redis-tribcreate host1:port1 … hostN:portN命令完成節點握手並確認槽位分配。伺服器上有多個Redis例項時,注意修改服務的埠、工作目錄、AOF和RDB檔名等配置。建立叢集時可以指定副本數,也可以在叢集建立完成後,將從節點逐個新增到叢集中去。

資料分佈:

Redis Cluster基於雜湊槽(分片)的方式將資料分佈到16384個槽中,每個Master節點負責一部分雜湊槽的資料儲存。Redis中的每個鍵都會被對映到這些雜湊槽的其中一個,叢集使用Hash公式CRC16(key)%16384來計算鍵key屬於哪個槽。

Redis的Smart客戶端在訪問叢集時,先獲取並快取雜湊槽和節點的對映關係,然後通過計算Key對應的雜湊槽編號查詢應該訪問的節點。為了配合叢集擴縮容、資料遷移等雜湊槽對映需要改變的操作,Redis服務端新增了MOVED、ASK兩種響應策略,前者通知客戶端所訪問的雜湊槽所在的新節點,後者則通知客戶端雜湊槽正在遷移到哪個節點。

主從複製:

Redis Cluster節點間使用非同步冗餘備份(Asynchronous Replication),不能保證資料的強一致性。可能出現資料丟失的場景:修改操作完成主節點上更新,當主節點回復客戶端成功後,增量改動未能同步到從節點,此時主節點異常(當機、故障轉移等),從節點成為主節點;客戶端路由表更新視窗期間,叢集內或許會有主從角色快速出現兩次切換,此時資料仍有可能寫錯節點,最終造成資料丟失。

雖然Redis主從複製不能保證強一致性,但在不出現主從切換的情況下,資料出現不一致的情況還是很難出現的。實際生產環境下,出現主從切換的概率不大,但仍建議業務系統要有容忍快取資料丟失的能力。

故障檢測:

Redis Cluster中的每個節點都儲存有一份其他已知節點的標識列表,其中有兩個標識是用於失效檢測,分別是 PFAIL 和 FAIL。當一個節點在超過NODE_TIMEOUT時間後仍無法訪問某個節點,他會將被檢測節點標識為PFAIL,表示可能失效;一個節點被大多數主節點確認不可達,則會標識為FAIL,表示已經失效。

每個節點定時向其他節點傳送Gossip訊息,訊息中包含一些隨機的已知節點的狀態。最終每個節點都能收到一份其他節點的標識。當節點被標記為FAIL時,就需要提升一個從節點來做主節點。

故障轉移:

當一個負責槽位數大於0的主節點處於FAIL狀態時,他的從節點可以自動的發起選舉。一旦某個從節點收到了大多數主節點的回應,那麼它將提升為新的主節點。另外,Redis Cluster提供了手動故障遷移的命令CLUSTER FAILOVER,可以在運維使用。

3. Redis Cluster在華泰證券背景介紹及建設現狀

2015年,隨著華泰證券網際網路金融自主研發的大規模投入,面對海量使用者併發場景,迫切需要建設統一化、服務化的分散式快取平臺。
通過對Redis Cluster、Codis及Twemproxy等開源Redis叢集解決方案進行驗證和對比,最終從效能、易維護、高可用等方面考慮,選擇Redis 3.2.0版本的Cluster模式作為公司級快取解決方案。Redis Cluster獲得了開源社群的持續支援,功能、特性一直在迭代改進。相比之下,Codis及Twemproxy社群活躍度較低,維護成本相對較高,吞吐量也略遜於Redis Cluster。
目前,在華泰證券建設有多套Redis Cluster資源池,總體叢集伺服器數量20餘臺。在交易時段,峰值訪問量超20萬次/秒,服務了30個以上應用系統,包括:行情中心、漲樂財富通、網際網路使用者中心等,在快取、分散式鎖、記憶體儲存、任務佇列等業務場景都有應用。

4. 實踐經驗

(1)高可用多活架構

如圖2所示,Redis Cluster資料節點採用同城三資料中心部署方式,通常其中兩個資料中心部署數量相等的機器,另一資料中心部署單臺機器。為加速重做從節點的速度,主機採用萬兆網路卡。為保證訪問快取的延時足夠小,跨資料中心之間的網路通訊採用獨立的萬兆波分通道。

圖2 Redis Cluster部署架構圖


實際部署時,需要調整Redis Cluster的Master節點分佈,要保證任意一個資料中心Master節點數小於叢集的一半。採取這樣的部署架構,如果單資料中心出現問題,另一箇中心能自動進行接管,業務系統可以無感知切換。

(2)Java客戶端層面的調優

1、推薦使用Jedis2.8.x及以上版本,關閉TestOnReturn和TestOnBorrow;
2、推薦使用Jedis的JedisPoolConfig,它是對GenericObjectPoolConfig的優化版本;
3、合理使用HGETALL、SMEMBERS等O(N)操作。

(3)服務端層面的優化

1、重新命名KEYS、FLUSHALL、FLUSHDB等耗時且危險的操作;
2、適度加大client-output-buffer-limitslave避免不必要的重做從節點;
3、適度加大repl-backlog-size和repl-backlog-ttl,值越大slave可丟失的時間越長;
4、AOF,關閉RDB,減少服務端fork操作造成的訪問出現卡頓的現象;
5、根據實際場景配置cluster-require-full-coverage為yes,減少叢集不可用的時間。

(4)Redis Cluster的功能限制

Redis cluster是分散式的Redis實現,具有一定的容錯性和線性可擴充套件性,這些特性犧牲了以下功能:
1、不能使用SELECT命令,不支援對多個槽位內的KEY進行操作,比如MSET、SUNION;
2、釋出訂閱功能不推薦使用,叢集規模越大,產生的網路流量越大;
3、採用Redis主從模式的應用,客戶端程式碼需要少量的改造才能升級到Cluster模式。

(5)問題跟進及版本更新

開源中介軟體難免出現Bug及其它效能問題,大部分問題開源社群都能找到問題的解決方案,積極的跟進社群討論是有效的避免生產事故的有效途徑。在實際使用中,我們發現了多個Redis的Bug,社群均有解決方案。目前,我們已經將生產環境上部分Redis節點升級到3.2.7版本,主要因為遇到以下問題:
1、從節點同步Ziplist後,List索引更新錯誤,造成從節點Crash;
2、Ziplist中成員長度增長,List索引更新錯誤,造成主節點和從節點的AOF重寫均失敗,產生大量臨時檔案。

(6)持續跟進

Redis 2.8.0版本開始引入PSYNC機制,PSYNC通過新增緩衝佇列,快取從節點斷開連線期間的資料變化增量,當從節點重新連線且快取佇列未溢位時,則可避免早期版本從節點重連後必然需要SYNC操作全量同步主節點資料的問題。
PSYNC可以有效地解決網路抖動造成的從節點短暫斷開連線的問題,但無法避免當主節點、從節點相繼出現網路失連、重啟、程式推出的情況發生後的全量資料同步和恢復,Redis 4.0引入PSYNC 2和PSYNC 3等新特性來解決相關問題。目前Redis 4.0仍處於驗證階段,需要持續驗證和密切關注。

5.典型場景

與其它開源的key-value記憶體儲存系統相比,Redis支援的資料更加豐富,常用的value資料型別包括:字串、雜湊表、連結串列、集合、有序集合。同時,Redis還內建了這些資料結構的常見操作。目前,Redis的應用已經非常廣泛,常見的使用場景包括:快取熱資料、計數器、佇列、分散式鎖、排行榜、新聞列表、評論等場景。Redis Cluster在華泰證券的新建資訊系統中也得到了廣泛的應用,使用的部分場景舉例如下:

行情截面

某些應用場景可能需要獲取某個市場或多個股票的最新行情,可以使用Redis的Hash結構來實現這個需求。示例程式碼如下:

新增或更新一隻股票的行情
HSETMD:XSHG:STOCKTYPE “601688.SH” 17.88 
獲取多隻股票最新行情
HMGET MD:XSHG:STOCKTYPE “601688.SH” “601689.SH”
獲取某個交易所所以股票最新行情,HGETALL操作為O(N)操作,不建議頻繁呼叫
HGETALL MD:XSHG:STOCKTYPE

K線

常見的K線為日K線或分鐘K線,以日K線為例,可以使用Redis的有序集合來實現,示例程式碼如下:
新增某隻股票2018年3月1的K線
ZADD KLINE:1DAY:601688.SH 20180301 kline_value
獲取某隻股票多天的K線
ZRANGEBYSCORE KLINE:1DAY:601688.SH 20180301 20180302

任務佇列

任務佇列用來在任務的生產者和消費者之間傳遞任務,實現任務的產生和任務執行模組間的鬆耦合。例項程式碼如下:
生產者生成一個任務task01
RPUSH TASK:QUEUE “task01”
消費者堵塞等待100秒等待任務,BLPOP是LPOP的堵塞版本
BLPOP TASK:QUEUE 100

6.未來規劃

隨著業務的不斷髮展,Redis Cluster在華泰證券內部已成為核心元件。未來重點進行PaaS平臺建設,加強叢集自動化災備;建立分級保障制度,對重點業務進行獨立管理。目前,Redis的最新版本4.0.x解決了Redis 3.2.x版本在面對網路劇烈抖動時,偶爾會出現部分分片所在的主從節點均不可用的情況。儘早驗證Redis 4.0.x版本的穩定性,制定有效的升級方案和計劃,也將是未來工作的重點之一。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/11310314/viewspace-2157228/,如需轉載,請註明出處,否則將追究法律責任。

相關文章