Redis實踐系列丨Codis數據遷移原理與優化

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,能夠更加快速的完成遷移。

相關文章
相關標籤/搜索