1. 程式人生 > >redis遷移資料之槽道討論

redis遷移資料之槽道討論

針對redis3.0之前的版本。在哨兵叢集管理的主從結構的叢集,結構如下

在這裡插入圖片描述

哨兵主從叢集和三個單獨redis節點的叢集同時存在。

遷移資料; hash一致性,擴容時,遷移資料大量減少;
但是這種遷移是運維工程師做不了的,需要了解key值計算過程

當前結構的redis節點的利用率太低
真正接收資料做資料處理的節點,9個節點中,接收key值儲存的只有3個

redis3.0版本之後,叢集的結構如下:

在這裡插入圖片描述

  • 1 所有的redis節點彼此互聯(包括所有的master和slave),使用內部的二進位制協議優化傳輸檔案,優化速度;

  • 2 節點的fail,選舉等,通過叢集中過半數量的主節點投票選舉(將哨兵的邏輯和主節點整合)

  • 3 客戶端jedis,連線叢集不一定要連線主節點,不一定要連線所有的節點,只需要通過連線其中一部分就可以,jedis傳遞的key值可以在叢集內部進行轉發,資料分片由叢集維護

  • 4 (與hash一致性不同)redis叢集把所有的主節點對映,投放到了一個0-16383個槽道(slot)(不一定平均分配) key值與槽道進行計算連通(雜湊取模運算,底層雜湊演算法CRC16) 資料–>slot–>master node

  • 5 當資料將要儲存到叢集時,由於連線的未必是master,slave也可以接收資料,key值計算結果0-16383整數,叢集中任何一個節點獲取這個整數後,都配將key值傳送到管理整數對應的槽道號的節點(主節點)進行儲存,從節點沒有管理槽道號的權利.

槽道號:
在這裡插入圖片描述

槽道號到底是什麼?如何在叢集中管理槽道的概念?

槽道引入後的好處:
可以單獨處理當前叢集的槽道管理
master01:0-5000
master02:5001-10000
master03:10001-16383

可以通過命令,重新劃分槽道時候,key值也需要跟著槽道遷移
維護人員可以用redis命令完成的過程

槽道到底是什麼?
1 節點在獲取key值的時候如何判斷當前key值對應的槽道號是否歸我管理
2 當key值的槽道號不歸當前節點管理時,當前節點如何知道正確的管理node

槽道的邏輯包含兩個部分:
16384位的二進位制位序列,16384個元素的共享陣列

每個節點上都有以上兩個資料,陣列在叢集的節點中內容完全一致,二進位制16384位序列主節點完全不一致的,從節點都是0;

2 進位制的位序列16384位(8位為例)
8位二進位制位序列
在這裡插入圖片描述

當前節點的位序列中下標號(計算出來的)對應的二進位制值如果是1,表示下標號同槽道號歸當前節點管理,如果是0,不管理
上圖的結果
8000節點管理的槽道:0,1,2
假設傳遞一個key=“name”–>slot num=4

所有的master都管理部分槽道號,二進位制的位序列在所有master中的值都不一樣,所有master的二進位制做位的或運算=16384位個全是1的二進位制,與預算=0

slave作為儲存資料,但是不管理槽道的節點,二進位制是0

cluster nodes 展示的10進位制的槽道號管理顯示,通過對二進位制計算的結果

共享陣列:所有叢集節點都儲存一個完全一致的陣列
16384個元素;陣列中的元素內容,儲存著當前元素下標對應槽道號的管理者的資訊;

在這裡插入圖片描述

當前節點判斷key值的對映結果不歸當前節點管理時,直接通過資料中獲取正確ip+port,將key值轉發出去;
登入的叢集客戶端呼叫cluster nodes方法檢視到的槽道狀態
->- migrating 匯出

槽道如何遷移:

- 1.重新create(cluster meet,手動分配槽道)

節點握手(3個節點,8000.8001.8002)
將叢集節點間的關係通過meet建立
登入8000需要使用127.0.0.1以外的ip

#redis-cli -h 106.75.85.179 -c -p 8000
8000>cluster meet 106.75.85.179 8001
[[email protected] redis-3.2.11]# redis-cli -h 106.75.85.179 -c -p 8000
106.75.85.179:8000> cluster meet 106.75.85.179 8001
106.75.85.179:8000> cluster meet 106.75.85.179 8002

- 2 指定槽道號(5461 5462 5461)
o指定某個節點的單個槽道,0 分配給8000,
8000>cluster addslots 0 1
在這裡插入圖片描述

無需完成手動輸入的5461個槽道分配
- 3 編寫shell指令碼

for i in {4..5460};do redis-cli -h 106.75.85.179 -c -p 8000 cluster addslots $i;done
for i in {5461..10922};do redis-cli -h 106.75.85.179 -c -p 8001 cluster addslots $i;done
for i in {10923..16383};do redis-cli -h 106.75.85.179 -c -p 8002 cluster addslots $i;done

直接執行提示
-bash: ./8000slots.sh: Permission denied
開啟執行sh指令碼的許可權

#chmod 777 *.sh(chmod代表變更檔案或者目錄的操作許可權,777表示所有使用者可讀可寫可執行後面跟著的檔案或資料夾)
#./8000slots.sh
#./8001slots.sh
#./8002slots.sh

- 4 槽道遷移(空槽道,非空槽道)

遷移1000號,源節點8000節點把1000導給目標8001節點
目標節點8001匯入1000號槽道(陣列對應元素中槽道狀態發生變化)
8001>cluster setslot 1000 importing 源節點id(8000)
會將當前節點8001中陣列元素對應的1000號槽道中的狀態從正常變成importing(-<-)
源節點8000匯出1000號槽道
8000>cluster setslot 1000 migrating 目標節點id
8000裡面的陣列發生變化,槽道狀態從正常變成匯出migrating(->-)

以上的兩步操作,不影響資料正常的set和get

通知所有節點該槽道遷移()

8000>cluster setslot 1000 node 目標節點id
8000節點二進位制變化(下標1000的二進位制值從1變成0)
陣列1000號下標的元素內容發生變化(從8000節點資訊,匯出狀態,轉化成8001節點資訊,正常狀態)
8001>cluster setslot 1000 node 目標節點id
8001的二進位制,1000號下標的二進位制值從0變成1,陣列變化成自己的節點資訊,槽道狀態正常
8002>cluster setslot 1000 node 目標節點id

- 5 非空槽道遷移(說明槽道已經掛鉤某一批key值,微調)

8000>set name xiaolaoshi
127.0.0.1:8002> set name xiaolaosih
-> Redirected to slot [5798] located at 106.75.85.179:8001
OK

- 6 遷移帶有資料的槽道5798(在8001節點),遷移到8002
目標節點匯入槽道

127.0.0.1:8002> cluster setslot 5798 importing 47dde9109e8a4ddfa6e9793b8c1029c48dbdc4a1
OK

源節點匯出槽道

106.75.85.179:8001> cluster setslot 5798 migrating c698022f3bed60d18433a9adf0bd7c4df7dc2e79
OK

將5798的資料從源節點遷移到目標節點
確定當前槽道的所有key值

8001>cluster getkeysinslot 5798 100(檢視5798上100範圍的key)
"name"
omget不知道叢集和分散式的,只能在一個節點上完成獲取key的任務
8001>mget name

- 7 遷移資料 name

migrate 106.75.85.179 8002 "name" 0 500 

“”:表示多個key進行遷移,後面緊跟著所有key的值
“name”:單個key值遷移,需要在字串中新增key值

106.75.85.179:8001> migrate 106.75.85.179 8002 "name" 0 500 
OK

檢視是否從8001遷移成功,mget name

127.0.0.1:8001> get name
(error) ASK 5798 106.75.85.179:8002
從8001遷移到8002 登入8001執行
8001>migrate 目標節點ip 目標節點埠

- 8 通知所有節點槽道遷移

8000> cluster setslot 5798 node 目標節點id
8001> cluster setslot 5798 node 目標節點id
8002> cluster setslot 5798 node 目標節點id

- 9 將剩下的三個節點8003.8004.8005分別對應一個主節點新增從節點**
先將8003,04,05 與叢集握手

8000>cluster meet ip port
8003>cluster replicate master-id

- 10 最終的叢集的結構
3個主節點,對應各自一個從節點
在這裡插入圖片描述

指令碼檔案如下:

8000slots

for i in {4..5460};do redis-cli -h 106.75.85.179 -c -p 8000 cluster addslots $i;done

8001slots

for i in {5461..10922};do redis-cli -h 106.75.85.179 -c -p 8001 cluster addslots $i;done

8002slots

for i in {10923..16383};do redis-cli -h 106.75.85.179 -c -p 8002 cluster addslots $i;done

總結:

redis3.0引入了redis叢集

  • 1 所有的redis節點彼此互聯(包括所有的master和slave),使用內部的二進位制協議優化傳輸檔案,優化速度;
  • 2 節點的fail,選舉等,通過叢集中過半數量的主節點投票選舉(將哨兵的邏輯和主節點整合)
  • 3 客戶端jedis,連線叢集不一定要連線主節點,不一定要連線所有的節點,只需要通過連線其中一部分就可以,jedis傳遞的key值可以在叢集內部進行轉發,資料分片由叢集維護
  • 4 (與hash一致性不同)redis叢集把所有的主節點管理若干個0-16383個槽道(slot)(不一定平均分配) key值與槽道進行計算連通(雜湊取模運算,底層雜湊演算法CRC16) 資料–>slot–>master node
    建立完集群后,啟動了一個8001客戶端,set name xiao,
    沒有為8001分配槽道的情況下,儲存失敗
  • 5 當資料將要儲存到叢集時,由於連線的未必是master,slave也可以接收資料,key值計算結果0-16383整數,叢集中任何一個節點獲取這個整數後,都配將key值傳送到管理整數對應的槽道號的節點(主節點)進行儲存,從節點沒有管理槽道號的權利,