技術前沿:分佈式緩存Redis Cluster在華泰證券的探索與實踐

摘要: Redis Cluster作爲最熱門的開源分佈式緩存,在券商領域會有怎樣的應用場景?本文從華泰證券的應用現狀出發,介紹了Redis Cluster在華泰證券的大規模實踐經驗。 引言Redis 是一個開源(BSD許可)的內存 Key-Value 存儲系統,它可以用作數據庫、緩存和消息中間件。

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 是抵禦突發海量訪問的有效手段。
基本原理及概念
Redis Cluster 整體設計是比較簡單的,集羣架構採用無中心節點的方式實現,集羣中的節點通過Gossip協議相互交換集羣狀態。客戶端無需代理直接訪問服務端,客戶端通過Hash算法計算出Key對應的哈希槽,然後直接訪問哈希槽對應的服務端節點。

Redis Cluster 的拓撲結構如下圖所示:

image

圖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,可以在運維使用。
Redis Cluster 在華泰證券背景介紹及建設現狀

2015年,隨着華泰證券互聯網金融自主研發的大規模投入,面對海量用戶併發場景,迫切需要建設統一化、服務化的分佈式緩存平臺。

通過對Redis Cluster、Codis及Twemproxy等開源Redis集羣解決方案進行驗證和對比,最終從性能、易維護、高可用等方面考慮,選擇Redis 3.2.0版本的Cluster模式作爲公司級緩存解決方案。Redis Cluster獲得了開源社區的持續支持,功能、特性一直在迭代改進。相比之下,Codis及Twemproxy社區活躍度較低,維護成本相對較高,吞吐量也略遜於Redis Cluster。

目前,在華泰證券建設有多套 Redis Cluster 資源池,總體集羣服務器數量20餘臺。在交易時段,峯值訪問量超 20萬次/秒,服務了30個以上應用系統,包括:行情中心、漲樂財富通、互聯網用戶中心等,在緩存、分佈式鎖、內存存儲、任務隊列等業務場景都有應用。

實踐經驗
(1)高可用多活架構
如圖2所示,Redis Cluster數據節點採用同城三數據中心部署方式,通常其中兩個數據中心部署數量相等的機器,另一數據中心部署單臺機器。爲加速重做從節點的速度,主機採用萬兆網卡。爲保證訪問緩存的延時足夠小,跨數據中心之間的網絡通信採用獨立的萬兆波分通道。

image

圖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仍處於驗證階段,需要持續驗證和密切關注。

典型場景

與其它開源的 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

未來規劃

隨着業務的不斷髮展,Redis Cluster 在華泰證券內部已成爲核心組件。未來重點進行 PaaS 平臺建設,加強集羣自動化災備;建立分級保障制度,對重點業務進行獨立管理。目前,Redis 的最新版本 4.0.x 解決了 Redis 3.2.x 版本在面對網絡劇烈抖動時,偶爾會出現部分分片所在的主從節點均不可用的情況。

儘早驗證Redis 4.0.x版本的穩定性,制定有效的升級方案和計劃,也將是未來工作的重點之一。請添加鏈接描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章