1. 程式人生 > >Redis叢集(一)安裝配置和簡便槽分配

Redis叢集(一)安裝配置和簡便槽分配

為什麼要用Redis叢集

Redis叢集是Redis提供的分散式資料庫方案,叢集通過**分片(sharding)**來進行資料提供,並提供複製和故障轉移功能。

學習記錄以下幾點:

  • 節點
  • 槽指派
  • 命令執行
  • 重新分片
  • 轉向
  • 故障轉移
  • 訊息

首先先看如何以叢集模式啟動Redis

1.複製三份配置redis.conf,修改埠號port和node.conf

#可選操作,該項設定後臺方式執行,
daemonize yes

port 7000
cluster-enabled yes
cluster-config-file nodes0.conf
cluster-node-timeout 5000
appendonly yes

記住三份檔案要在不同資料夾下(例如/7001/redis.conf、/7002/redis.conf···)

node.conf雖然此配置的名字叫"叢集配置檔案",但是此配置檔案不能人工編輯,它是叢集節點自動維護的檔案,主要用於記錄叢集中有哪些節點、他們的狀態以及一些持久化引數等,方便在重啟時恢復這些狀態。通常是在收到請求之後這個檔案就會被更新。

配置檔案結構:

Redis/
├── 7000
|   ├── redis.conf
|   ├── nodes0.conf
├── 7001
|   ├── redis.conf
|   ├── nodes1.conf
├── 7002
|   ├── redis.conf
|
├── nodes2.conf

2.依次通過redis-server根據具體配置啟動

# redis-server /7000/redis.conf

如果遇到以下錯誤:

Sorry, the cluster configuration file nodes.conf is already used by a different Redis Cluster node. Please make sure that different nodes use different cluster configuration files.

請確認node.conf檔名是否修改正確

我是以前臺方式啟動的,所以能看到列印以下列印資訊:

10992:M 10 Apr 13:48:38.266 * No cluster configuration found, I'm f745788c4c24711a11c8ad516ead9a485e5b1dbb

此時表示redis已經以叢集模式啟動了


節點

一個Redis叢集通常有多個節點(Node)組成,在剛開始的時候,每個節點都是互相獨立的,它們都處於一個只包含自己的叢集當中,要元件一個真正可工作的叢集,我們必須將各個獨立的節點連線起來,構成一個包含多個節點的叢集。

連線各個節點的工作可以使用CLUSTER MEET命令,可以讓node節點與io和port所指定的節點進行握手
# CLUSTER MEET <ip> <port>

測試,用三個獨立的節點(本地開啟7000、7001、7002三個埠)

# redis-cli -c -p 7000
27.0.0.1:7000> CLUSTER NODES
f745788c4c24711a11c8ad516ead9a485e5b1dbb :[email protected] myself,master - 0 0 0 connected
可以看出,現在叢集只包含700自己一個節點

開始節點之間的連線:

127.0.0.1:7000> CLUSTER MEET 127.0.0.1 7001
OK
127.0.0.1:7000> CLUSTER NODES
2a1035a6642f8f1020c279c8a69ce66ff7eb564b 127.0.0.1:[email protected] master - 0 1523341290344 1 connected
f745788c4c24711a11c8ad516ead9a485e5b1dbb 127.0.0.1:[email protected] myself,master - 0 0 0 connected
127.0.0.1:7000> CLUSTER MEET 127.0.0.1 7002
OK
127.0.0.1:7000> CLUSTER NODES
3110ed887330d428e1b544932dc22b1fcbd3fa45 127.0.0.1:[email protected] master - 0 1523341327519 2 connected
2a1035a6642f8f1020c279c8a69ce66ff7eb564b 127.0.0.1:[email protected] master - 0 1523341328553 1 connected
f745788c4c24711a11c8ad516ead9a485e5b1dbb 127.0.0.1:[email protected] myself,master - 0 1523341327000 0 connected

通過CLUSTER NODES可以看出,現在叢集中包含了三個節點。

叢集資料結構

clusterNode結構儲存了一個節點的當前狀態,比如節點的建立時間節點的名字、節點當前的配置紀元節點的IP地址和埠號等等。

結構如下定義:

 struct clusterNdoe {
   //建立節點的時間
   mstime_t ctime;
   
   //節點的名字
   char name[REDIS_CLUSTER_NAMELEN];
   
   //節點標識
   int flags;
   
   //節點當前的配置紀元,用來實現故障轉移
   uint64_t configEpoch;
   
   //節點的IP地址
   char ip[REDIS_IP_STR_LEN];
   
   //節點的埠號
   int port;
   
   //儲存連線節點所需的有關資訊
   clusterLink *link;
   
   ···
}

每個節點都儲存著一個clusterState結構,這個結構在當前節點描述叢集當前所處的狀態,例如叢集是線上還是下線,叢集包含多少個節點,叢集當前的配置紀元等。

typedef struct clusterState {
  // 指向當前節點的指標
  clusterNode *myself;
  
  //叢集當前的配置紀元,用於實現故障轉移
  uint64_t currentEpoch;
  
  //叢集當前的狀態:線上OR下線
  int state;
  
  //叢集節點名單(包括自己)
  dict *nodes;
  
  ···
}

槽指派

Redis叢集通過分片的方式來儲存資料庫中的鍵值對:叢集的整個資料庫被分為16384個槽(slot),資料庫中的每個鍵都屬於這16384個槽的其中一個,叢集中的每個節點可以處理0個或最多16384個槽。

當資料庫中的16384全部槽都有節點在處理時,表示叢集處於上線狀態;否則,處於下線狀態。

通過CLUSTER_INFO進行叢集狀態檢視

127.0.0.1:7000> cluster info
# state顯示是fail,因為沒有處理槽
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3
cluster_size:0
cluster_current_epoch:2
cluster_my_epoch:0
cluster_stats_messages_ping_sent:1261
cluster_stats_messages_pong_sent:1350
cluster_stats_messages_meet_sent:2
cluster_stats_messages_sent:2613
cluster_stats_messages_ping_received:1350
cluster_stats_messages_pong_received:1263
cluster_stats_messages_received:2613

使用redis-trib.rb建立叢集並分配槽

在節點中通過CLUSTER ADDSLOTS [slot …]

# 將0-5000槽指派給7000負責
127.0.0.1:7000>CLUSTER ADDSLOTS 0 1 2 3 ... 5000

大霧!!!一個一個將槽位打出來不現實,所以使用redis-trib.rb幫助我們進行簡單叢集配置,但redis-trib.rb是由ruby語言編寫的所以需要安裝ruby環境。

發現繞來繞去,REDIS的叢集安裝還需要RUBY環境和使用gem安裝redis介面。

給大夥一個安裝傳送門

注意:
Mac通過Homebrew沒有src目錄,gem install redis後找不到redis-trib.rb,被折磨很久後,直接去GITHUB下載這個檔案

# redis-trib.rb create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002
>>> Creating cluster
>>> Performing hash slots allocation on 3 nodes...
Using 3 masters:
127.0.0.1:7000
127.0.0.1:7001
127.0.0.1:7002
M: f745788c4c24711a11c8ad516ead9a485e5b1dbb 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 2a1035a6642f8f1020c279c8a69ce66ff7eb564b 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: 3110ed887330d428e1b544932dc22b1fcbd3fa45 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join.
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: f745788c4c24711a11c8ad516ead9a485e5b1dbb 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 2a1035a6642f8f1020c279c8a69ce66ff7eb564b 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: 3110ed887330d428e1b544932dc22b1fcbd3fa45 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

踩坑:之前通過CLUSTER MEET,讓各個節點進行握手,所以使用redis-trib.rb會報下面這個錯誤

[ERR] Node 127.0.0.1:7001 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.

解決方法:
在每個節點查詢nodes編號後,使用CLUSTER FOTGET命令

cluster forget 3110ed887330d428e1b544932dc22b1fcbd3fa45

接著重新輸入命令
redis-trib.rb create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002

檢視槽分派情況

使用CLUSTER SLOTS查詢

127.0.0.1:7000> CLUSTER SLOTS
1) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 7002
      3) "3110ed887330d428e1b544932dc22b1fcbd3fa45"
2) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 7001
      3) "2a1035a6642f8f1020c279c8a69ce66ff7eb564b"
3) 1) (integer) 0        //起始槽編號
   2) (integer) 5460     //結束槽編號
   3) 1) "127.0.0.1"     //IP
      2) (integer) 7000  //PORT
      3) "f745788c4c24711a11c8ad516ead9a485e5b1dbb" //NODE編號

從上圖可以看出,每個節點負責處理自己對應的槽。

一個節點除了會將自己負責處理的槽記錄在clusterNode結構的slots屬性和numslots屬性之外,還會將自己的slots陣列通過訊息傳送給叢集中的其他節點,以此來告知其他節點自己目前負責處理哪些槽。