準備工作
在 github 上下載 redis 源碼,編譯
./configure
make
LZ 下載的 redis 版本是 3.0.7
編譯成功後,在源碼的根目錄下的 src 目錄中,會生成對應的可執行文件
redis-server redis 服務器啓動程序
redis-cli redis客戶端程序
redis-trib.rb 這是一個ruby程序,可以用於創建集羣、檢查、刪除節點等
redis-sentinel 哨兵程序,能夠監控redis HA和主備主機
創建集羣
在 redis 官網也介紹了集羣的搭建方法 [https://redis.io/topics/cluster-tutorial]
LZ 共使用了四個虛擬機,用於創建集羣,每天虛擬機三個節點,分別是一個 RHEL,三個Ubuntu Server 16.04,IP地址分別如下:
192.168.192.166,以下簡稱166
192.168.192.132,以下簡稱132
192.168.192.133,以下簡稱133
192.168.192.134,以下簡稱134
創建節點
在 166 主機創建 config/clusters/
目錄,再在這個目錄下創建 7001, 7002 和 7003 三個目錄,分別以目錄名稱作爲端口號(前提是你的機器上這些端口號沒有被佔用, netstat -pnl
查看端口號)
創建一個通用配置文件 redis-common.conf
daemonize yes
tcp-backlog 511
timeout 0
tcp-keepalive 0
loglevel debug #開放最大日誌級別,能夠通過日誌信息查看更多細節
database 16
slave-serve-stale-data yes #redis在複製的時候也可訪問
#slave 只讀
slave-read-only yes
repl-disable-tcp-nodelay yes
slave-priority 100
#打開 aof
appendonly yes
appendfsync everysec #在不清楚的這個配置的情況,redis 推薦設置這個參數爲 everysec
no-appendfsync-on-rewrite yes #關閉aof rewite的時候對新的寫操作進行 fsync
auto-aof-rewrite-min-size 64mb
lua-time 5000
#打開redis集羣
cluster-enabled yes
#節點互聯超時時的閥值
cluster-node-timeout 15000
cluster-migration-barrier 1
#slow log
slowlog-log-slower-than 10000
slowlog-max-len 128
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
再根據不同的節點,爲每一個節點創建一個特殊的配置文件,比如 redis-7001.conf
,並通過 include 包含通用配置
include redis-common.conf
port 7001
bind 192.168.192.166
logfile "" #日誌文件保存路徑+日誌文件名,建議方便的話,可以保存在對應的節點目錄下
dir "" #rdb, aof ,nodes.conf 文件的保存路徑
appendfilename "appendonly-7001.aof"
cluster-config-file "nodes-7001.conf" #這個配置文件是由redis自動創建的,裏面記錄的集羣節點的一些信息,比如master 節點,slave 節點的IP,端口號以及狀態(是否failed)
maxmemory 100m
maxmemory-policy allkeys-lru #內存耗盡時的淘汰策略
#remove any keys according to the LRU algorithm
auto-aof-rewrite-percentage 100
爲每一個虛擬機創建好三個節點之後,就開始啓用節點
啓動節點
166主機
redis-server redis-7001.conf
redis-server redis-7002.conf
redis-server redis-7003.conf
132主機
redis-server redis-7004.conf
redis-server redis-7005.conf
redis-server redis-7006.conf
133主機
redis-server redis-7007.conf
redis-server redis-7008.conf
redis-server redis-7009.conf
134主機
redis-server redis-7010.conf
redis-server redis-7011.conf
redis-server redis-7012.conf
節點啓動後,查看日誌信息,觀察是否均啓動成功
創建集羣
redis cluster 在設計的時候,就考慮到了去中心化,去中間件,也就是說,集羣中的每個節點都是平等的關係,都是對等的,每個節點都保存各自的數據和整個集羣的狀態。每個節點都和其他所有節點連接,而且這些連接保持活躍,這樣就保證了我們只需要連接集羣中的任意一個節點,就可以獲取到其他節點的數據。
Redis 集羣沒有並使用傳統的一致性哈希來分配數據,而是採用另外一種叫做哈希槽 (hash slot)的方式來分配的。redis cluster 默認分配了 16384 個slot,當我們set一個key 時,會用CRC16算法來取模得到所屬的slot,然後將這個key 分到哈希槽區間的節點上,具體算法就是:CRC16(key) % 16384。
Redis 集羣會把數據存在一個 master 節點,然後在這個 master 和其對應的salve 之間進行數據同步。當讀取數據時,也根據一致性哈希算法到對應的 master 節點獲取數據。只有當一個master 掛掉之後,纔會啓動一個對應的 salve 節點,充當 master 。
需要注意的是:必須要3個或以上的主節點,否則在創建集羣時會失敗,並且當存活的主節點數小於總節點數的一半時,整個集羣就無法提供服務了。
當所有的節點都創建好後,在 src 目錄中有一個文件 redis-trib.rb
(前面介紹了這個文件),用這個工具創建集羣。
Usage: redis-trib <command> <options> <arguments ...>
set-timeout host:port milliseconds
del-node host:port node_id
reshard host:port
--from <arg>
--pipeline <arg>
--yes
--timeout <arg>
--slots <arg>
--to <arg>
create host1:port1 ... hostN:portN
--replicas <arg>
help (show this help)
info host:port
check host:port
call host:port command arg arg .. arg
add-node new_host:new_port existing_host:existing_port
--master-id <arg>
--slave
rebalance host:port
--weight <arg>
--threshold <arg>
--pipeline <arg>
--auto-weights
--simulate
--timeout <arg>
--use-empty-masters
fix host:port
--timeout <arg>
import host:port
--replace
--from <arg>
--copy
For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
上面是這個工具的用法,該文件是使用 ruby 編寫的,首先在你的環境中需要安裝 ruby
RHEL 中安裝
yum install ruby
Ubuntu 中安裝
sudo apt-get install ruby
LZ因爲環境比較無語,主機無法連接網絡,所以都是使用的本地倉庫的形式,具體如何創建網絡倉庫,可以去找找資料,這裏不多說,Ubuntu 創建本地倉庫比較簡單,就是掛在一個鏡像,然後使用 apt-cdrom,在 source.list 文件中就會增加一個源,指向的就是掛在的鏡像目錄。
安裝好 ruby 之後,執行 redis-trib.rb
文件可能仍會報錯
`require`: no such file to load -- rubygems (LoadError)
`require`: no such file to load -- redis (LoadError)
這個是因爲你的環境中沒有安裝 rubygems 和 ruby redis (在沒網的環境中,手動下載依賴包簡直就是噩夢)
下載 rubygems: [https://rubygems.org/page/download]
ruby redis: [https://rubygems.org/gems/redis],這是一個ruby 的redis 客戶端
下載好 rubygems 後,執行
ruby setup.rb --help
能夠查看詳細的細節,安裝執行 gem
ruby setup.rb
安裝完成之後,即可安裝 ruby redis 客戶端了
gem install -l redis-3.2.1.gem
OK,環境配置好後,開始創建集羣
./redis-trib.rb create --replicas 2 192.168.192.166:7001 192.168.192.166:7002 192.168.192.166:7003 192.168.192.132:7004 192.168.192.132:7005 192.168.192.132:7006 192.168.192.133:7007 192.168.192.133:7008 192.168.192.133:7009 192.168.192.134:7010 192.168.192.134:7011 192.168.192.134:7012
創建12個節點,4個 master 節點,每一個 master 節點有 2 個 slave 節點。
如下圖所示表示成功
集羣操作
1. 查看節點信息
使用 redis-trib.rb info IP:PORT
./redis-trib.rb info 192.168.192.166:7001
2. 檢查集羣狀態
使用 redis-trib.rb check IP:PORT
3. 停止其中一個master,再啓動,觀察變化
當前集羣運行狀態是 OK 的
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:12
cluster_size:4
cluster_current_epoch:17
cluster_my_epoch:1
cluster_stats_messages_sent:43924
cluster_stats_messages_received:11595
一共12個節點,有4個master節點,在 7001 的節點下,查看 node-7001.conf 這個文件(這個文件是 redis 自動生成的)
這個文件記錄了集羣中所有相關的能夠到達的節點的信息,包括master的狀態(是否是failed)
我們來看一下,每一個master節點都有哪些slave,info replication
能夠清晰的查看slave 或者 master 的信息
master: 192.168.192.166 7003
ip:192.168.192.133,port:7007
ip:192.168.192.134,port:7012
master: 192.168.192.166 7002
ip:192.168.192.132,port:7005
master: 192.168.192.132 7004
ip:192.168.192.132,port:7006
ip:192.168.192.133,port:7009
master: 192.168.192.166 7001
ip:192.168.192.133,port:7008
ip:192.168.192.134,port:7011
這是當前我們的集羣分佈,上面的是 master,下面的兩個是該 master 的兩個 slave
現在我們來關閉其中一個 master,7004
redis-cli -h 192.168.192.132 -p 7004
shutdown
關閉之後再來查看 node-7001.conf 這個文件信息,此時發現,有一個 master 顯示的是 failed
當 master failed 的時候,redis 會從它的從服務器中選一個作爲新的 master,然後另一個從服務器將作爲新的 master 的 slave,再來看集羣分佈
master: 192.168.192.132 7006
ip:192.168.192.133,port:7009
master: 192.168.192.166 7003
ip:192.168.192.133,port:7007
ip:192.168.192.134,port:7012
master: 192.168.192.166 7002
ip:192.168.192.132,port:7005
master: 192.168.192.166 7001
ip:192.168.192.133,port:7008
ip:192.168.192.134,port:7011
在沒有停止 7004 之前,7004 作爲 master,7006 和 7009 作爲它的 slave,在將 7004 停止之後,7006 成爲了新的 master,並且 7009 變成了它的 slave,當我們再次重新啓動 7004 時,redis 不會重新把它作爲 master,它將作爲新的 master 7006 的一個 slave
4. 集羣失敗
redis 集羣必須要有三個或以上的 master 節點,否則集羣將創建失敗,目前集羣的狀態時 ok,如果我們關閉 166 和 132 主機,查看集羣狀態爲 fail
5. 添加新的 master 節點
在 132 主機上創建 8000 節點,在 133 主機上創建 8001 節點 (配置文件與其他節點的相同,只需要修改一下相應的文件保存路徑即可)
啓動節點
redis-server redis-8001.conf
redis-server redis-8000.conf
添加節點
./redis-trib.rb add-node 192.168.192.132:8000 192.168.192.133:7004
出現如下錯誤
[ERR] Node 192.168.192.132:8000 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
這個節點之前添加了一次,沒有添加成功,導致節點非空,添加失敗,解決辦法:
1) 登陸數據庫,將數據進行刪除 flushdb
2) 將節點下的集羣配置文件刪除,即 node-8000.conf,redis 自動生成的文件
3) 刪除節點下的 aof , rdb 文件等本地備份文件
再次添加節點
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 192.168.192.132:8000 to make it join the cluster.
[OK] New node added correctly.
節點添加成功。查看集羣的狀態發現節點數成了13個
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:13
cluster_size:4
cluster_current_epoch:24
cluster_my_epoch:0
cluster_stats_messages_sent:284
cluster_stats_messages_received:284
當前集羣的分佈如下所示
master: 192.168.192.132 7005
ip:192.168.192.134,port:7010
ip:192.168.192.166,port:7002
master: 192.168.192.132 7006
ip:192.168.192.133,port:7009
ip:192.168.192.132,port:7004
master: 192.168.192.166 7003
ip:192.168.192.134,port:7012
ip:192.168.192.133,port:7007
master: 192.168.192.132 8000
master: 192.168.192.166 7001
ip:192.168.192.133,port:7008
ip:192.168.192.134,port:7011
新添加的 8000 端口是 master 節點,它不包含任何數據,因爲沒有包含任何的 slot。新添加的都爲主節點,當集羣需要將某個節點升級爲新的主節點時,這個節點不會被選中。
爲新節點分配 slot
redis-trib.rb rehashed 192.168.192.132:8000
按照提示操作
#選擇要遷移的 slot 數量
How many slots do you want to move (from 1 to 16384)? 500
What is the receiving node ID? 81e71239d85d4112e87c5fe00d513f879c980118
#all 表示從所有的 master 重新分配
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1:all
Ready to move 500 slots.
Source nodes:
M: 030197fec21c3192c0f8938ad276f8c8062c6410 192.168.192.166:7001
slots:0-4095 (4096 slots) master
2 additional replica(s)
M: c6e30b67bc201f4f48bdf5fe9d88209505e2f0d9 192.168.192.132:7005
slots:4096-8191 (4096 slots) master
2 additional replica(s)
M: 70d2ed1edd1035972927a7c8415ca9d0c941d21d 192.168.192.166:7003
slots:8192-12287 (4096 slots) master
2 additional replica(s)
M: c63aac7105f9601915e65ef0d3ff45b0b3f0a7ec 192.168.192.132:7006
slots:12288-16383 (4096 slots) master
2 additional replica(s)
M: 1a260ae8c08a9ee1b4d856e0fcf190c271590cf0 192.168.192.133:8001
slots: (0 slots) master
0 additional replica(s)
Destination node:
M: 81e71239d85d4112e87c5fe00d513f879c980118 192.168.192.132:8000
slots: (0 slots) master
0 additional replica(s)
Resharding plan:
Moving slot 0 from 030197fec21c3192c0f8938ad276f8c8062c6410
......
Do you want to proceed with the proposed reshard plan (yes/no)? yes
Moving slot 0 from 192.168.192.166:7001 to 192.168.192.132:8000:
......
6. 添加新的 slave 節點
節點添加與上面添加 master 的前面步驟相同
1. 創建節點目錄和節點配置文件,啓動節點
2. redis-trib.rb add-node new-ip:new-port exist_ip:exist_port
3. 這樣,添加上的節點爲 master 節點,然後使用 redis-cli 連接,輸入命令
cluster replicate node-id
即添加成功,node-id 可以通過查看命令 CLUSTER NODES
查看,也可以直接查看節點的 node.conf
文件
NOTE:在線添加 slave 節點時,需要 dump 整個 master 進程,並傳遞到 slave,再由 slave 加載 rdb 文件到內存, rdb 傳輸過程中可能無法提供服務,整個過程需要消耗大量的I/O。
7. 刪除 master 節點
刪除節點之前,需要使用 reshard 移除該 master 的全部 slot,然後才能刪除節點,接收 slot 的節點必須是 master 節點
./redis-trib.rb reshard 192.168.192.134:8003
How many slots do you want to move (from 1 to 16384)? 500
What is the receiving node ID? c6023463d9f33e4c5ca72fdc85eb4c7d95b258a5
*** The specified node is not known or not a master, please retry.
What is the receiving node ID? 1a260ae8c08a9ee1b4d856e0fcf190c271590cf0
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1:81e71239d85d4112e87c5fe00d513f879c980118
Source node #2:done
Ready to move 500 slots.
Source nodes:
M: 81e71239d85d4112e87c5fe00d513f879c980118 192.168.192.132:8000
slots:0-124,4096-4220,8192-8316,12288-12412 (500 slots) master
1 additional replica(s)
Destination node:
M: 1a260ae8c08a9ee1b4d856e0fcf190c271590cf0 192.168.192.133:8001
slots: (0 slots) master
0 additional replica(s)
Resharding plan:
Moving slot 0 from 81e71239d85d4112e87c5fe00d513f879c980118
......
移除所有的 slot 之後,刪除空 master 節點
redis-trib.rb del-node 192.168.192.132:8000 '81e71239d85d4112e87c5fe00d513f879c980118'
8. 刪除 slave 節點
#redis-trib.rb del-node ip:port 'node-id'