Codis介紹html
Codis 是一種Redis集羣的實現方案,與Redis社區的Redis cluster相似,基於slot的分片機制構建一個更大的Redis節點集羣,對於鏈接到codis的Redis客戶端來講, 除了部分不支持的命令外,與鏈接開源的 Redis Server 沒有明顯的區別, 客戶端代碼基本須要進行修改,Codis-proxy會根據訪問的key進行slot的計算,而後轉發請求到對應的Redis-server,對於客戶端來講,中間的codis-proxy是不可見的,所以根據客戶業務的須要,可使用codis構建大規模的Redis 服務,或者僅僅是用於把請求分擔多個Redis-server提升系統的吞吐量。redis
與業界著名的twproxy相比,除了支持Redis的轉發,coids還支持不停機的數據遷移,使用戶能夠在容量或者吞吐量要求有變化時,輕鬆進行節點的增減,本文主要對codis的遷移原理進行分析,並提出一個可行的優化點。json
本文是基於codis3.0版本。網絡
(圖片來自網絡)app
Codis遷移實現原理函數
Codis-dashboard在啓動時,運行了4個後臺線程(goroutine),包括後臺redis狀態同步、proxy狀態同步、slot事件處理、sync事件處理,並提供了slot相關的RestFUL API進行slot與Redis-group歸屬關係的定義、遷移的定義和觸發。性能
以下結構定義一個slot與Redis-group的歸屬關係和遷移關係,GroupId表示索引爲Id的slot所屬的redis-group,而Action用於表示一次遷移,Action.TargetId表示該slot要遷移的目標redis-group的Id,Action.State表示遷移的狀態,主要有Pending、Preparing、Prepared、Migrating、Finished幾種狀態。測試
type SlotMapping struct {優化
Id int `json:"id"`線程
GroupId int `json:"group_id"`
Action struct {
Index int `json:"index,omitempty"`
State string `json:"state,omitempty"`
TargetId int `json:"target_id,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
} `json:"action"`
}
手動進行一次遷移過程,能夠用以下命令來觸發:
codis-admin --dashboard=ADDR -slot-action --create --sid=ID --gid=ID,好比把slot 10遷移到group 5,則能夠執行」 codis-admin --dashboard=ADDR -slot-action --create --sid=10 --gid=5」
若是是把多個slot遷移到同一個server,則可使用以下命令,一次性來定義若干個遷移操做,codis-admin --slot-action --create-range --beg=ID --end=ID --gid=ID,好比把slot 10~15遷移到group 5,則能夠執行」 codis-admin --dashboard=ADDR -slot-action –create--range --beg=10 –end=15 --gid=5」。
一次遷移的執行過程當中,slot的Action的狀態會發生變化,過程爲:
也能夠觸發codis進行rebalance,命令爲:codis-admin --dashboard=ADDR –rebalance --confirm,codis會自動把slot往一些新加入的節點進行遷移,使各個節點負責的slot均衡。
Codis遷移的測試
經測試,對於一個64G規模的集羣(由8個節點組成,每一個節點8G),使用redis-benchmark寫滿數據,每一個key的value長度爲32字節,總共寫入341446298(3.4億)條數據,擴容到128G,即對其中的512個slot進行遷移。
測試結果以下:
從測試結果來看,遷移速度很是慢,每遷移一個slot須要花費基本1個小時,所以使用codis時,須要監控數據量,當數據不夠時,須要進行及時的擴容,不然當空間不夠時的故障處理和恢復時間可能影響線上業務。
Codis遷移代碼分析及瓶頸分析
從測試結果來看,遷移速度確實很是慢,極端狀況下可能會影響線上業務,所以對遷移過程進行分析和優化就頗有必要,下邊對關鍵的實現代碼handleSlotRebalance 、StartDaemonRoutines、ProcessSlotAction進行解讀,並分析優化改進的地方。
01
handleSlotRebalance實現分析
這個函數的主要邏輯分爲三部分:
1)找到須要遷移的slot;
2)爲每一個新節點分配slot;
3)生成遷移操做;
上面的代碼的邏輯是:
1)根據節點個數和slot槽數(固定的1024),計算每一個節點上應該負責的slot槽數,表示爲bound;
2)對每一個redis-group,找到須要遷移出去的slot,表示爲pending;
生成遷移計劃:
1)遍歷全部的redis-group,對於已有的slot小於應該負責的slot槽數的,就要遷移一些槽進來;
2)全部的redis-group,決定須要遷移進來的slot列表,表示爲plans;
遍歷遷移計劃,使用create actionRange生成一系列的slot action,並保存到etcd,下一步就須要由後臺線程去etcd中取出slot操做進行分別處理。
02
StartDaemonRoutines
這個代碼是在dashboard啓動時就啓動的後臺任務,每隔5秒鐘觸發一次slot操做,且只會運行一個slot操做任務。
03
ProcessSlotAction實現分析
分爲兩步Topom.SlotActionPrepare和Topom.processSlotAction。
從上面代碼能夠看出:
下邊再分析processSlotAction的實現:
能夠看出:
04
瓶頸分析
從上面的分析能夠得出:
這個設計的好處是,遷移過程對客戶業務的影響很小,可是也有一些明顯的缺點:
因爲擴容通常會有必定的提早量,且會選在業務低峯期進行,所以能夠對該遷移方案進行優化,能夠在不對業務訪問形成太大的影響的前提下提升遷移效率。
Codis代碼優化
根據上面對遷移實現的分析,優化的思路爲:
一、Slot遷移並行化
從代碼實現的分析,有2個點能夠選擇:
最終處理代碼簡單化的考慮,選擇了方案2,同時考慮到以下幾點:
以下優化代碼,啓動至多10個線程進行slot事件的處理。
同時修改SlotActionPrepare,選擇一個狀態爲Pending且沒有歸屬於同一個redis-server的slot,進行處理。
二、Multikey遷移
修改redis-server的遷移指令,支持一次遷移多個key,爲了靈活性,把遷移的個數從外部傳入,代碼比較顯而易見,參考以下:
Codis遷移優化測試結果
通過驗證,對於一個64G規模的集羣,使用redis-benchmark寫滿數據,每一個key的value長度爲32字節,總共寫入341446298(3.4億)條數據,擴容到128G,即對其中的512個slot進行遷移。最終測試結果爲:
所以,通過優化後遷移性能有極大的提高。固然當前的配置也是考慮到了儘可能不影響客戶的業務訪問,一次遷移的數據量並非最大化的,在某些狀況下,能夠修改配置,一次遷移更多的key,能夠更加快速的完成遷移。