餓了麼Redis Cluster集群化演進
2017運維/DevOps在線技術峰會上,餓了麼運維負責人程炎嶺帶來題為“餓了麼Redis Cluster集群化演進”的演講。本文主要從數據和背景開始談起,並對redis的治理進行分析,接著分享了redis cluster的優缺點,重點分析了corvus,包括commands、邏輯架構和物理部署等,最後分享了redis的運維和開發,並作了簡要總結,一起來瞧瞧吧。
以下是精彩內容整理:
近幾個月,運維事件頻發。從“爐石數據被刪”到“MongoDB遭黑客勒索”,從“Gitlab數據庫被誤刪”到某家公司漏洞被組合攻擊。這些事件,無一不在呐喊——做好運維工作的重要性。然而,從傳統IT部署到雲,人肉運維已經是過去式,雲上運維該怎麼開展?尤其是雲2.0時代,運維已經向全局化、流程化和精細化模式轉變。與此同時,人工智能的發展,“威脅論”也隨之襲來——運維是不是快要無用武之地了?如何去做更智能的活,當下很多運維人在不斷思考和探尋答案。
Redis Cluster在業內有唯品會、優酷藍鯨等很多公司都已經在線上有了一定規模的Redis Cluster集群,那麼,餓了麼是怎樣從現有的Redis技術遷移到Redis Cluster集群上的呢?
背景和數據
2015-2016年是餓了麼的業務爆炸式增長階段,訂單量從幾十w到到峰值900w/天,在增長的過程中我們也遇到了一些問題,我們有服務化治理訴求、應用性能和穩定訴求、人肉運維成本訴求,並且還要為未來的PAAS平台池化準備。
橫坐標是訂單量,縱坐標是集群數量,在多機房下整個集群規模是double的,可以看到,千萬訂單的集群規模大概在200個,在一個機房內我們有近200套集群,近4T數據在Redis裏麵,整個節點數大約在10000個左右。
上圖表示在高峰期時每天不同訂單量下,整個Redis集群承載OPS的需求。
使用場景
外賣行業的使用場景要結合業務來看,所有需要高性能、高並發、降級數據庫場景下都用到了Redis做緩存,包括用戶端、商戶端和物流配送,搜索排序、熱賣、畫像等目前也是往Redis裏推送,除了緩存外,還有各類cache、計數器、分布式鎖等。
為什麼會考慮向Redis Cluster演進呢?
因為Redis存在很多問題,比如單點的內存上限受限製,將Redis當成DB或cache混用,共用一個redis、大key阻塞整個實例,經常需要擴容、擴容很痛苦,使用複雜且基礎環境非標、存在各種配置,監控缺失以及不能統一配置等諸多問題。
治理
由於Redis請求量太大,打滿了機器網卡,所以在2016年5月啟動了治理redis的項目。
在自研選型部分,在OPS推廣治理時我們與業內成熟技術做了比較,包括Redis vs redis Cluster,以及Twenproxy vs Codis vs Redis Cluster,比較了單節點的redis和redis Cluster,還有業內經過生產考驗的proxy,最後決定自研自己的Redis Cluster + proxy。
Redis Cluster 的優缺點
為什麼選擇redis cluster作為我們的底層存儲呢?
Redis cluster自帶遷移功能,性能快、高可用,支持在線分片,豐富集群管理命令等。自研proxy在初期快速在生產上應用時候可以省略掉這部分,讓redis cluster本身給我們提供這項功能就足夠了。
Redis cluster也有一些不足:
- Client 實現複雜,需要緩存slot mapping關係並及時更新;
- Client不成熟導致提高開發難度;
- 存儲和分布式邏輯耦合,節點太多時節點之間的檢測占大量網卡帶寬;
- 3.0.6版本前,隻能單個key遷移,並且同時隻允許一個slot處於遷移狀態。
Corvus
圖中為corvus時序設計,可以看到,actor到後麵的redis,中間的proxy、client和server是在corvus中實現的邏輯,proxy處理connect操作,接收用戶的請求發送到client,server最終實現命令的處理。我們分成三個分類,對於單key、特殊命令和多key的處理,對複合命令操作做了單獨操作,並對返回結果做聚合,同時還有一些特殊命令,比如cluster命令的處理邏輯。
corvus封裝了redis cluster 協議,提供redis 協議,這樣用原來成熟的redis client操作redis cluster集群,接入到corvus,這時可以做到無縫的改動;擴容縮容應用無感知,corvus服務是注冊的機製,對應用程序來說,連接是通過一層本地proxy,我們對應用程序提供SDK,但目前我們通過本地proxy連接接入corvus已經能夠滿足大部分應用;corvus實時緩存了slots mapping,它會不停的發送corvus notes去獲取redis node與slots mapping的關係,並更新到corvus本身的緩存中,還有Multiple Thread、Lightweight和Reuseport support等。
Corvus commands
- Corvus支持Pipeline;
- Modified commands,對複合命令做spring操作,我們已經對命令本身進行了修改,但可能對我們看監控數據有疑惑,統計端節點命中率與應用程序命中率可能不一樣;
- Restricted commands;
- Unsupported commands,比如對GU的處理,目前還沒有在redis cluster中使用GU的應用,暫時不會支持。
Corvus performance
圖中為corvus的測試報告,這是很極端的壓測情況,set/get可以達到140萬QPS數據。
Corvus 邏輯架構
可以看到,底層存儲用redis cluster,web console通過後端ruskit操作redis cluster,當我們注冊redis cluster時,APPid存儲在storage裏,監控部分我們通過Esm agent發送到Grafana,corvus本身也會采集server log發送到Statsd去收集,corvus agent去部署時首先要初始化corvus agent注冊到host console裏,通過corvus agent去拉起或回收某一套redis cluster,Huskar是我們的集中配置管理,對應到我們後端的zk技術。
Corvus 物理部署
Corvus的物理部署如圖所示,上麵是應用程序端,應用程序連接到本地的corvus服務端口,corvus服務端口作為本地的sam port,一個corvus實例對應到redis cluster的一些master節點,會部署在不同的物理服務器上,根據不同的和數去創建corvus服務實例以及redis節點。
這裏有兩層proxy,首先連接本地的sam,也就是go proxy,go proxy這層提供應用服務化、本地接入,corvus是redis cluster proxy這一層,兩層proxy意味著兩層的性能損耗,在這個基礎上,我們也做了針對redis cluster相同的直連的性能損失,對比來看,proxy層性能損耗相比運維成本以及服務化成本而言,是可以接受的。
Redis 運維和開發
Redis運維
- 我們將redis移交數據庫團隊運維
- 統一redis 物理部署架構
- 標準化redis/corvus 服務器以及單機容量
- 設定redis 開發設計規範
- 設定redis資源申請流程,做好容量評估
- 完善監控,監控分corvus和redis cluster兩部分,跟進全鏈路壓測,從最前端打進來,到底層的redis和數據庫
- 根據壓測結果做隔離關鍵集群,比如整個外賣後端和商戶的redis,將它們做單獨隔離,redis cluster本身對網卡要求很高,分專用資源和公共資源,專用資源的corvus或redis cluster機器獨棧給到APPid,公共資源是混布情況,我們隻需監控網卡流量、cpu等
- 升級萬兆網卡,新采購的服務器都是萬兆配置
Redis 開發約定
Redis開發約定如下:
- Key 格式約定:object-type:id:field。用":"分隔域,用"."作為單詞間的連接,對於整個field怎樣分隔,我們有很多種改法;
- 禁止大k-v,我們基於全鏈路壓測,比如一套集群有多種類型的pattern的key,其中某一個的key value很長,占用內存很大,我們就要告訴開發者像這種使用姿勢是不對的,須被禁止;
- 隻用作cache, Key TTL設置;
- 做好容量評估,由於redis cluster的遷移限製,所以前期我們要做好容量評估,比如整套集群申請100G,我們需要計算需要的內存容量以及所在的應用場景負載;
- 設定集群上限,規定redis cluster集群數不超過200,單個節點容量4~8G;
- 接入統一為本地goproxy
Redis 改造
我們要定義一個節奏,對redis進行改造,具體如下:
1. 將Redis 遷移cluster
2. 完善system、redis、corvus監控
3. 對線上redis拆分、擴容
4. 非標機器騰挪下線
5. 大key、熱節點、大節點掃描,比如同一個redis cluster集群某個節點明顯高於其它節點,我們會做節點分析和key的分析等
6. 網卡Bond,多隊列綁定
7. 修改jedis源碼,加入matrix埋點上報etrace,就可以在etrace看到每個應用trace到整條鏈路到哪一個端口,它的響應時間、請求頻次、命中率等。
經驗總結
對於redis我們可謂經驗豐富,總結如下:
- Redis 更適合cache,cluster下更不合適做持久化存儲
- 一致性保證,不做讀寫分離(盡管corvus支持)
- 單實例不宜過大,節點槽位要均衡
- 發現問題,複盤,積累經驗
- 不跨機房部署,性能優先
- 異地多活通過訂閱消息更新緩存
- 大部分的故障都是由於hot-key/big-key
- 關心流量,必要時立刻升級萬兆
遺留問題
目前redis還不夠自動化,某些操作還是分成多個步驟來實現,大集群Reshard擴容慢;遇到版本升級問題時,可以新起一條集群;Sam->corvus->redis鏈路分析,應用程序在etrace上訪問端口會很慢,需要從redis和corvus層層自證等;多活跨機房寫緩存同步;我們通過定時任務的發起AOF/RDB來保證數據盡快恢複,實際上我們是關閉掉的;冷數據也是不夠完善的,還有集群自愈,當遇到問題時我們可以快速拉起另外一套集群將數據更新過去,或者通過數據更新預熱將緩存更新過去。
池化
我們在根據全鏈路壓測時的一些特性或數據去做集群隔離,分放公共池和專用池,以及對整個池內資源做buffer的監控;資源申請隻需關注容量以及使用方式,無需關心機器;另外,新申請以及擴容縮容按組(group)操作,運維操作自動化,不需要登錄到某個機器上執行某個命令。
開發自助
我們最終的目標是在緩存部分實現開發自助,具體步驟如下:
1. 開發自助申請redis 資源
2. 填入demo key/value,自動計算容量
3. 狀態,告警推送,對線上實時運行情況的透明化
4. 各類文檔齊全
目前我們還做不到,需要OPS團隊幹預開發。
最後更新:2017-04-24 21:32:59