Redis之Redis Cluster的使用
一、Redis Cluster 簡介
Redis Sentinel 水平擴容一直都是一個痛點,因爲水平擴容牽涉到數據的遷移。遷移過程一方面要保證自己的業務是可用的,一方面要保證儘量不丟失數據所以數據能不遷移就儘量不遷移。針對這個問題,Redis Cluster就應運而生了。
Redis Cluster 是 Redis 的分佈式解決方案,在3.0版本正式推出,有效地解決了 Redis 分佈式方面的需求。當遇到單機內存、併發、流量等瓶頸時,可以採用 Cluster 架構方案達到負載均衡的目的。
二、Redis Cluster 和哨兵集羣的比較
哨兵集羣:本質上還是一個主從模式下的集羣方案,增加一個選舉機制,當主節點宕機之後會從所有節點中選出新的主節點,選舉機制的實現依賴於sentinel
進程。這種模式基本已經可以實現高可用,讀寫分離 ,但是在性能,存儲量上還是不夠好。
cluster
集羣:是Redis
的一種分佈式解決方案,在3.0版本中正式提出,這個方案把整個數據集按照分區規則映射到多個節點的問題,即把數據集劃分到多個節點上,每個節點負責整個數據的一個子集。Redis Cluster
槽的範圍是0 ~ 16383。槽是集羣內數據管理和遷移的基本單位。主要目的是爲了方便數據的拆分和集羣的擴展,每個節點負責一定數量的槽。通過slot = CRC16(key)&16383
計算所在卡槽的節點位置。
三、搭建Redis Cluster集羣
結構圖
配置文件
# ip監控
bind 0.0.0.0
protected-mode no
# 端口 修改
port 7000
# 後臺運行
daemonize yes
# 工作目錄
dir ./
# pid 修改
pidfile "/var/run/redis_7001.pid"
# 日誌名 修改
logfile "redis_7001.log"
# RDB同步數據 修改
dbfilename "dump_7001.rdb"
# AOF同步
appendonly yes
# 修改
appendfilename "appendonly_7001.aof"
# AOF 策略
appendfsync everysec
# 失效消息通知配置
# notify-keyspace-events "xE"
# 開啓cluster, 去掉註釋
cluster-enabled yes
# 自動生成 修改
cluster-config-file cluster_7001.conf
# 節點通信時間
cluster-node-timeout 15000
將這配置文件複製六份需要修改的地方,修改之後。
啓動腳本
#!/bin/bash
# 整個測試環境的根目錄
ROOT_PATH=/opt/redis-cluster-self-service
# 存放redis-server的目錄
REDIS_SERVER=/opt/redis-cluster-self-service/redis-master/bin/redis-server
echo ">>> 清除啓動的 Redis cluster 集羣...";
for item in `ps -ef | grep -v grep | grep redis | awk '{print $2}'`
do
echo $item
kill -9 $item
done
echo ">>> 成功清除啓動的 Redis cluster 集羣...";
echo ">>> 啓動redis cluster 集羣...";
for item in {0..5}
do
$REDIS_SERVER $ROOT_PATH/redis-node-700${item}/redis-700${item}.conf;
if [ $? == 0 ];then
# sleep 5s;
echo "啓動端口爲700${item}的Redis服務器成功";
else
echo "啓動端口爲700${item}的Redis服務器失敗";
fi
done
echo ">>> 啓動redis cluster 集羣結束";
echo ">>> 檢測是否啓動成功...";
ps -ef | grep -v grep | grep redis
啓動集羣
[root@long-test redis-cluster-self-service]# ./start.sh # chmod +x start.sh賦予權限
>>> 清除啓動的 Redis cluster 集羣...
17171
>>> 成功清除啓動的 Redis cluster 集羣...
>>> 啓動redis cluster 集羣...
啓動端口爲7000的Redis服務器成功
啓動端口爲7001的Redis服務器成功
啓動端口爲7002的Redis服務器成功
啓動端口爲7003的Redis服務器成功
啓動端口爲7004的Redis服務器成功
啓動端口爲7005的Redis服務器成功
>>> 啓動redis cluster 集羣結束
>>> 檢測是否啓動成功...
root 17237 1 0 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7000 [cluster]
root 17242 1 0 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7001 [cluster]
root 17244 1 0 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7002 [cluster]
root 17249 1 0 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7003 [cluster]
root 17257 1 4 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7004 [cluster]
root 17259 1 11 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7005 [cluster]
[root@long-test redis-cluster-self-service]#
連接其中一個Redis
[root@long-test redis-cluster-self-service]# redis-cli -p 7000 # 連接7000端口
127.0.0.1:7000> set name 1234
(error) CLUSTERDOWN Hash slot not served # 未分配卡槽
分配卡槽
[root@long-test redis-cluster-self-service]# redis-cli --cluster create 192.168.252.131:7000 192.168.252.131:7001 192.168.252.131:7002 192.168.252.131:7003 192.168.252.131:7004 192.168.252.131:7005 --cluster-replicas 1
--cluster-replicas 1
:是表示主節點和從節點爲1:1的比例(一主一從)的結構。
分配的卡槽情況:
最後分配結果:
再次連接其中一個redis
[root@long-test redis-cluster-self-service]# redis-cli -p 7000
127.0.0.1:7000> set name 123456
(error) MOVED 5798 192.168.252.131:7001 # 仍然不能寫入值,提示我們key對應的卡槽在7001這個redis上
127.0.0.1:7000>
我們需要在連接的時候添加一個重定向的參數:
[root@long-test redis-cluster-self-service]# redis-cli -p 7000 -c # -c redis的客戶端會爲我們自動重定向
127.0.0.1:7000> set name 123456
-> Redirected to slot [5798] located at 192.168.252.131:7001
OK
192.168.252.131:7001> # 現在已經在redis的7001這個服務器上了
四、 Redis Cluster 擴容
複製上面的配置文件,然後啓動服務:
7006
和7007
就是我們新需要擴容的redis
服務。
Redis
將節點擴容到Redis
集羣中
先添加一個主節點
# 將7006 擴容主節點
[root@long-test redis-cluster-self-service]# redis-cli --cluster add-node 192.168.252.131:7006 192.168.252.131:7000
擴容主節點之後的集羣節點情況
再添加一個從節點:
# 將7007 擴容從節點
[root@long-test redis-cluster-self-service]# redis-cli --cluster add-node 192.168.252.131:7007 192.168.252.131:7000 --cluster-slave --cluster-master-id 22ebb08e9461445d8f77ca650fca7d1a777928aa
# --cluster-master-id 後面添加的是主節點的ID, 從上圖命令中可以得到
再次查看添加從節點之後集羣情況:
這樣就說明我們添加節點成功了,但是我們還需要分配卡槽,這樣的話添加的節點纔可以讀寫數據。
分配卡槽
在我們剛纔是三臺的時候每臺redis
分到的卡槽是:16384/3=5461
,其中一個節點時5462
個,剩下兩個是5461
。
現在我們擴容的時候是4臺redis
, 平均分配到四臺上,那我們每一臺16384/4=4096
。
分配的方法有兩種方式:
all
: 均攤,從當前的每個節點中分配一部分到新的節點中done
: 選擇某一個節點進行分配。
接下來就是yes
,等待分配移動節點結束,在這期間是無法讀寫的。
分配之後的卡槽情況:
分配之後我們進行讀寫:
[root@long-test redis-cluster-self-service]# redis-cli -p 7000 -c
127.0.0.1:7000> set yyyy 123456 # 可以寫入7006節點的數據了
-> Redirected to slot [10980] located at 192.168.252.131:7006
OK
192.168.252.131:7006>
五、 Redis Cluster 縮容
縮容的命令:
[root@long-test redis-cluster-self-service]# redis-cli --cluster reshard 192.168.252.131:7000 --cluster-from 532c30c5d91a4011145ce7e92d4949fdf056bf73 --cluster-to 51e81d10bbd2cb399e91273fc52831c24a82dac9 --cluster-slots 4096
# --cluster-from 要減少的節點ID
# --cluster-to 要移動到的節點ID
# --cluster-slots 4096 移動的節點
縮容之後的卡槽情況:
六、Redis Cluster 宕機自動選舉
將7006
節點殺掉,我們看一下7007
是否會變爲主節點:
將7006
節點啓動之後我們會發現變爲從節點:
七、 Springboot整合Redis Cluster
這裏我們每個redis節點配置一個密碼:
在redis的配置文件中添加一個密碼:
requirpass 123456
重新創建分配卡槽
[root@long-test ]# redis-cli --cluster create 192.168.252.131:7000 192.168.252.131:7001 192.168.252.131:7002 192.168.252.131:7003 192.168.252.131:7004 192.168.252.131:7005 192.168.252.131:7006 192.168.252.131:7007 -a 123456 --cluster-replicas 1
# -a 123456 是爲了設置整個集羣的密碼123456
依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
配置文件
spring:
redis:
password: 123456
cluster:
# 所有節點列表
nodes:
- 192.168.252.131:7000
- 192.168.252.131:7001
- 192.168.252.131:7002
- 192.168.252.131:7003
- 192.168.252.131:7004
- 192.168.252.131:7005
- 192.168.252.131:7006
- 192.168.252.131:7007
# 最大重定向次數
max-redirects: 4
lettuce:
pool:
# 連接池最大連接數
max-active: 8
# 連接池最大阻塞等待時間
max-wait: -1ms
# 連接池中最大空閒連接數
max-idle: 10
# 連接池中最小空閒連接數
min-idle: 5
使用:
@RestController
public class RedisController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/set_key")
public String setKey() {
stringRedisTemplate.opsForValue().set("order_name", UUID.randomUUID().toString());
System.out.println("設置的key");
return "success";
}
}
查看我們寫入的值:
[root@long-test redis-cluster-self-service]# redis-cli -p 7000 -a 123456 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7000> get order_name # 重定向到7001節點
-> Redirected to slot [4291] located at 192.168.252.131:7001
"407f7841-3054-4775-ac00-9b03d502a164"
192.168.252.131:7001>
八、主從、哨兵、集羣的辨析
最後我們在看一下Redis
中多機數據庫實現的這三種模式的總結和辨析:
- 主從複製:集羣方式裏最簡單的。它主要是基於Redis的主從複製特性架構的。通常我們會設置一個主節點,N個從節點;默認情況下,主節點負責處理使用者的IO操作,而從節點則會對主節點的數據進行備份,並且也會對外提供讀操作的處理。
- 哨兵集羣:基於主從模式做的一定變化,它能夠爲Redis提供了高可用性。在實際生產中,服務器難免不會遇到一些突發狀況:服務器宕機,停電,硬件損壞等。這些情況一旦發生,其後果往往是不可估量的。而哨兵模式在一定程度上能夠幫我們規避掉這些意外導致的災難性後果。這種模式下每臺redis服務器都存儲相同的數據,很浪費內存;並難以支持現線擴容,橫向擴展比較麻煩。
- Redis 集羣是一個提供在多個Redis間節點間共享數據的程序集。也就是分佈式存儲,也就是說每臺redis節點上存儲不同的內容。並且仍然具有主從和哨兵的優點。當其中一個主節點宕機需要半數以上的主節點確定纔會從從節點中選舉出新的主節點。