1. 程式人生 > >Redis 分散式叢集,分配Slots

Redis 分散式叢集,分配Slots

某天在開啟了Redis叢集之後,發現網站沒法正常訪問了,發現Nginx-lua 中的 Redis 丟失連線 …

叢集下線

問題表現

通過檢視 openrestry log 發現 lua指令碼報錯 :

2018/06/12 17:48:20 [error] 23272#0: *75665 lua entry thread aborted: runtime error: /usr/local/openresty/nginx/lua/access_by_redis.lua:67: attempt to compare boolean with number
stack traceback:
coroutine 0
: /usr/local/openresty/nginx/lua/access_by_redis.lua: in function </usr/local/openresty/nginx/lua/access_by_redis.lua:1>, client: 66.249.65.116, server: www.leon0204.com, request: "GET /wechat-858.html HTTP/1.1", host: "www.leon0204.com"

從而 Nginx 返回 500,測試 Redis set 發現是叢集處於下線狀態導致的 :
這裡寫圖片描述

原因分析

  1. 開啟叢集
    假設A伺服器上有 127.0.0.1:6379

    127.0.0.1:6370 兩個 Redis 節點。在 節點 6379 的 redis.conf中開啟 cluster-enabled yes ,那麼節點 6379 就處於一個只包含自己的叢集中。

  2. 構建叢集
    127.0.0.1:6379 傳送命令:
    CLUSTER MEET 127.0.0.1:6370
    就把 6370 節點 拉到了 6379 所在的叢集中。

  3. 槽指派
    Redis叢集通過分片的方式來儲存資料庫的所有鍵值對:整個資料庫被分成16384 個 Slot ,資料庫鍵空間的所有鍵被分配到這 16384 個槽中的一個,每個node 處理 0~16384 個槽。當16384個槽有任意1個沒有被處理,叢集處於 fail
    下線狀態,否則處於上線 狀態。

猜想是有一些槽沒有被分配處理,進行分配槽

分配槽

檢視叢集狀態:

127.0.0.1:6379> CLUSTER INFO
cluster_state:fail
cluster_slots_assigned:7
cluster_slots_ok:7
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:1
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0

有 7 個 Slot 已經被分配,由於有 slots沒有分配乾淨,所以叢集處於 fail 下線狀態,進行分配 slots

[email protected]:~# redis-cli -h 127.0.0.1  -p 6379 -a Qqq291838322siwei cluster addslots {0..5000}
(error) ERR Slot 0 is already busy
[email protected]:~# redis-cli -h 127.0.0.1  -p 6379 -a Qqq291838322siwei cluster addslots 5
OK
...
...
[email protected]:~# redis-cli -h 127.0.0.1  -p 6379 -a Qqq291838322siwei cluster addslots {8400..12000}
(error) ERR Slot 11955 is already busy
[email protected]:~# redis-cli -h 127.0.0.1  -p 6379 -a Qqq291838322siwei cluster addslots {8400..11954}
OK
[email protected]:~# redis-cli -h 127.0.0.1  -p 6379 -a Qqq291838322siwei cluster addslots {13001..16383}
OK

可以看到這裡不斷有一些slots : 1151 1389 1909 5798 6918 8399 11955
已經被分配了,這是為什麼呢,是不是我把 6379 加入叢集之後,已經預設給我分配了這些 槽呢?先來看看分配完成叢集的狀態,和slot_assigned的數目:

127.0.0.1:6379> CLUSTER NODES
151ce5ca0524b02c7af07402dcb40f5d678f7bb1 :6379 myself,master - 0 0 0 connected 0-16383

127.0.0.1:6379> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:1
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0

# 可以正確的 set 了
127.0.0.1:6379> set leon leon0204
OK
127.0.0.1:6379>

驗證一下,分配過程中那些 斷點 槽 ,也就是單節點叢集 6379主機的所有 key ,和他們被分配到的槽 :

127.0.0.1:6379> KEYS *
1) "pyq"
2) "user:183.234.61.216:freq"
3) "leon0204"
4) "name"
5) "funet"
6) "goodsId"
7) "test"

剛剛我分配 0,16383 個槽給 當前node節點時,提示槽X已經busy 的 有

1151 1389 1909 5798 6918 8399 11955
我們知道,當叢集被建立之後,叢集的整個資料庫就會被分配到 16383 個槽中,類似於分片的概念 。那麼是否是我之前的這些key ?
那麼,我們檢視 這些key 被分配的槽號

127.0.0.1:6379> CLUSTER KEYSLOT "pyq"
(integer) 1151
127.0.0.1:6379> CLUSTER KEYSLOT "user:183.234.61.216:freq"
(integer) 1909
127.0.0.1:6379> CLUSTER KEYSLOT "leon0204"
(integer) 11955
127.0.0.1:6379> CLUSTER KEYSLOT "name"
(integer) 5798
127.0.0.1:6379> CLUSTER KEYSLOT "funet"
(integer) 8399
127.0.0.1:6379> CLUSTER KEYSLOT "goodsId"
(integer) 1389
127.0.0.1:6379> CLUSTER KEYSLOT "test"
(integer) 6918

正好和上面的 addslots 過程中,衝突的 slots 吻合 ,7個key 對應7 個 slot