准備
環境配置
docker redis鏡像
# docker 拉取redis鏡像
docker pull redis
# redis 鏡像詳情
docker inspect redis
redis版本為 5.0.4
docker 集群網絡
# 創建屬於redis的集群網絡
docker network create redis-cluster-net
網關Gateway: 172.18.0.1
集群掛載目錄
- 打算開啟6個節點, 3對主從節點搭建集群
- 開放7000~7005端口, 即根據端口號創建6個目錄, 每個目錄下建立data目錄和配置文件redis-{port}.conf
# 主目錄
dir_redis_cluster='/home/lingsh/study/redis/redis-cluster'
# docker redis集群網關
gateway='172.18.0.1'
# 節點地址號 從2開始
idx=1
# 逐個創建各節點目錄和配置文件
for port in `seq 7000 7005`; do
# 創建存放redis數據路徑
mkdir -p ${dir_redis_cluster}/${port}/data;
# 通過模板個性化各個節點的配置文件
idx=$(($idx+1));
port=${port} ip=`echo ${gateway} | sed "s/1$/$idx/g"` \
envsubst < ${dir_redis_cluster}/redis-cluster.tmpl \
> ${dir_redis_cluster}/${port}/redis-${port}.conf
done
配置文件模板
# 基本配置
## 開放端口
port ${port}
## 不作為守護進程
daemonize no
## 啟用aof持久化模式
appendonly yes
# 集群配置
## 開啟集群配置
cluster-enabled yes
## 存放集群節點的配置文件 系統自動建立
cluster-config-file nodes-${port}.conf
## 節點連接超時時間
cluster-node-timeout 50000
## 實際為各節點網卡分配ip
cluster-announce-ip ${ip}
## 節點映射端口
cluster-announce-port ${port}
## 節點總線端口
cluster-announce-bus-port 1${port}
cluster-slave-validity-factor 10
cluster-migration-barrier 1
cluster-require-full-coverage yes
docker redis集群
配置並啟動
# 創建容器配置並運行
for port in `seq 7000 7005`; do
docker run --name redis-${port} --net redis-cluster-net -d \
-p ${port}:${port} -p 1${port}:1${port} \
-v ${dir_redis_cluster}/${port}/data:/data \
-v ${dir_redis_cluster}/${port}/redis-${port}.conf:/usr/local/etc/redis/redis.conf redis \
redis-server /usr/local/etc/redis/redis.conf
done
- 使用配置文件啟動
- 查看各節點所分配到的ip是否符合
redis集群配置
# 查看集群功能是否開啟 info cluster
docker exec -it redis-7000 redis-cli -p 7000 info cluster
節點連接
docker exec -it redis-7000 redis-cli -p 7000 cluster meet 172.18.0.3 7001
docker exec -it redis-7000 redis-cli -p 7000 cluster meet 172.18.0.4 7002
docker exec -it redis-7000 redis-cli -p 7000 cluster meet 172.18.0.5 7003
docker exec -it redis-7000 redis-cli -p 7000 cluster meet 172.18.0.6 7004
docker exec -it redis-7000 redis-cli -p 7000 cluster meet 172.18.0.7 7005
配置主從
# cluster nodes
# fc342e637ed176a493753f208faf5ed908d9d63e 172.18.0.2:7000@17000 master - 0 1570462918000 1 connected
# ff2e6f9d20811f0fb2cf574062224e307f41812f 172.18.0.3:7001@17001 master - 0 1570462919000 0 connected
# ee6083ba6a6f1d77918122dbdb5ca10f607d0ab5 172.18.0.4:7002@17002 master - 0 1570462919752 2 connected
# d01dfa4adef8d3b41a525807b0193b662a33d567 172.18.0.5:7003@17003 master - 0 1570462920756 3 connected
# 1c0daa91884d3d239bdcbd7f38112668a023a967 172.18.0.6:7004@17004 master - 0 1570462918749 4 connected
# 8632ecc5b7b684cdab50f4c1b19e59e9c2998657 172.18.0.7:7005@17005 master - 0 1570462918000 5 connected
# 設置7001節點為7000節點的從節點
docker exec -it redis-7001 redis-cli -p 7001 cluster replicate fc342e637ed176a493753f208faf5ed908d9d63e # 7001 --> 7000
# 設置7003節點為7002節點的從節點
docker exec -it redis-7003 redis-cli -p 7003 cluster replicate ee6083ba6a6f1d77918122dbdb5ca10f607d0ab5 # 7003 --> 7002
# 設置7005節點為7004節點的從節點
docker exec -it redis-7005 redis-cli -p 7005 cluster replicate 1c0daa91884d3d239bdcbd7f38112668a023a967 # 7005 --> 7004
slots分配
# 將16384個槽分配到3個主節點去, 每個節點平均分的5461個槽
# 7000 0~5460
docker exec -it redis-7000 redis-cli -p 7000 cluster addslots {0..5460}
# 7002 5461~10920
docker exec -it redis-7002 redis-cli -p 7002 cluster addslots {5461..10920}
# 7004 10920~16383
docker exec -it redis-7004 redis-cli -p 7004 cluster addslots {10921..16383}
測試
redis-cli
Java
public class TestRedisConnect {
@Test
public void connectCluster() {
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("127.0.0.1", 7000));
nodes.add(new HostAndPort("127.0.0.1", 7001));
nodes.add(new HostAndPort("127.0.0.1", 7002));
nodes.add(new HostAndPort("127.0.0.1", 7003));
nodes.add(new HostAndPort("127.0.0.1", 7004));
nodes.add(new HostAndPort("127.0.0.1", 7005));
JedisCluster cluster = new JedisCluster(nodes, 5000);
System.out.println(cluster.get("hello"));
cluster.set("test2", "6739");
System.out.println(cluster.get("test2"));
Map<String, String> inviteePhone = new HashMap<>(5);
inviteePhone.put("inviterID", "1001");
inviteePhone.put("status", "0");
// hash表 批處理
cluster.hmset("inviteePhone", inviteePhone);
System.out.println(cluster.hget("inviteePhone", "inviterID"));
System.out.println(cluster.hget("inviteePhone", "status"));
}
}
遭遇問題
問題一 ERR This instance has cluster support disabled
進入節點 輸入cluster info
查看該節點是否開啟集群功能, 報錯
探查原因
redis-cli
使用config get *
命令查看配置信息docker inspect [id/name]
查看容器內部配置信息
問題二 Fatal error, can't open config file
無法打開配置文件
探查原因
- 不是權限問題
- redis使用配置文件 需要redis-server + docker
內部
的配置文件
docker run --name redis-7000 -d -p 7000:6379 \
-v /home/lingsh/study/redis/redis-cluster/7000/data:/data \
-v /home/lingsh/study/redis/redis-cluster/7000/redis.conf:/usr/local/etc/redis/redis.conf redis \
redis-server /home/lingsh/study/redis/redis-cluster/7000/redis.conf
docker run --name redis-7000 -d -p 7000:6379 \
-v /home/lingsh/study/redis/redis-cluster/7000/data:/data \
-v /home/lingsh/study/redis/redis-cluster/7000/redis.conf:/usr/local/etc/redis/redis.conf redis \
redis-server /usr/local/etc/redis/redis.conf
問題三 Could not connect to Redis at 127.0.0.1:6379: Connection refused
> docker run --name redis-7000 -d -p 7000:6379 \
-v /home/lingsh/study/redis/redis-cluster/7000/data:/data \
-v /home/lingsh/study/redis/redis-cluster/7000/redis.conf:/usr/local/etc/redis/redis.conf redis \
redis-server /usr/local/etc/redis/redis.conf
> docker exec -it redis-7000 redis-cli
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected>
容器啟動成功, docker logs
查看日志也沒什么問題
探查問題
- 開始以為自己的啟動方式有誤
docker run --name [] -d -p 7000:6379 -v [] -v [] redis redis-server [conf file]
- 進入容器內部探查
docker exec -it redis-7000 bash
cat /usr/local/etc/redis/redis.conf
發現配置文件都配置上去了, 可以查看內容
- 在容器內部使用bash啟動redis-server
redis-server []
啟動不了 說是7000端口
被占用了
???等等
容器內部7000端口被啟用了?
- 配置文件的port是給容器內部使用的
- 將配置文件更改為
port 6379
即可以使用redis-cli
默認打開redis命令行 - 配置文件為
port 7000
,docker
映射7000端口給容器7000, 通過redis-cli -p 7000
打開
> docker run --name redis-7000 -d -p 7000:7000 \
-v /home/lingsh/study/redis/redis-cluster/7000/data:/data \
-v /home/lingsh/study/redis/redis-cluster/7000/redis.conf:/usr/local/etc/redis/redis.conf redis \
redis-server /usr/local/etc/redis/redis.conf
> docker exec -it redis-7000 redis-cli -p 7000
# redis.conf
# port 7000
問題四 docker內部的redis無法meet其他redis
127.0.0.1:7000> cluster nodes
0964944aaf47f9beabc9aa3e34ba321fc77a01c1 0.0.0.0:7001@17001 handshake - 1569747263643 0 0 `disconnected`
a55bc0de87a024b905b0f4223c7441a49b980a19 :7000@17000 myself,master - 0 0 0 connected
探查問題
- 容器網絡問題
- 可以直接使用host解決
--net=host
告訴Docker
不要將容器網絡放到隔離的命名空間中,即不要容器化容器內的網絡。此時容器使用本地主機的網絡
,它擁有完全的本地主機接口訪問權限。容器進程可以跟主機其它root
進程一樣可以打開低范圍的端口,可以訪問本地網絡服務比如D-bus
,還可以讓容器做一些影響整個主機系統的事情,比如重啟主機。因此使用這個選項的時候要非常小心。如果進一步的使用--privileged=true
,容器會被允許直接配置主機的網絡堆棧。
- 也可以使用bridge橋接網絡(不過會相對麻煩一些)
- 需要給
redis.conf
添加cluster-announce-ip/port/bus-port
等參數
通過
docker network inspect redis-cluster-net | grep Gateway
查找到網關ip 遞增修改cluster-announce-ip
參數 --redis-cluster-net 是自己創建的bridge網絡模式docker network create redis-cluster-net
- 在啟動容器時, 添加
-p 1700*:1700*
指定宿主機與容器redis總線端口映射 - redis內部連接時,
cluster meet [cluster-announce-ip] [port]
- 需要給
- 個人選擇了第二種方式, 這種方式較為復雜一些, 需要通過網關來給各個節點分配不同的ip
問題五 JedisMovedDataException: MOVED 10520 172.18.0.6:7004
探查問題
- API使用問題
原來:redis.clients.jedis.Jedis
--> Jedis集群接口redis.clients.jedis.JedisCluster
問題六 java.lang.NumberFormatException: For input string: "7000@17000"
探查問題
- Jedis版本問題
由於redis集群的采用的版本是4.1的, 在maven的pom.xml中將jedis的版本改成2.9以上的就可以了
參考資源
maven項目中使用redis集群報錯: java.lang.NumberFormatException: For input string: "7006@17006"
參考資源
Redis 集群教程
Redis學習筆記六——搭建redis集群(非分布式真正的cluster)
docker redis 集群(cluster)搭建
Redis進階實踐之十一 Redis的Cluster集群搭建
【Redis入門】-集群(手動搭建)
Linux_基於Docker搭建Redis集群
redis集群搭建之官方redis cluster 搭建實踐
利用docker搭建redis cluster(集群) ——3主3從
docker 部署 redis-cluster集群
Docker 網絡實現
個人簡單控制容器的腳本
#!/bin/bash
# 外部輸入命令
com=$1
# 主目錄
dir_redis_cluster='/home/lingsh/study/redis/redis-cluster'
# redis集群網關
gateway='172.18.0.1'
case ${com} in
create)
idx=1;
for port in `seq 7000 7005`; do
# 創建存放redis數據路徑
mkdir -p ${dir_redis_cluster}/${port}/data;
# 通過模板個性化各個節點的配置文件
idx=$(($idx+1));
port=${port} ip=`echo ${gateway} | sed "s/1$/$idx/g"` \
envsubst < ${dir_redis_cluster}/redis-cluster.tmpl \
> ${dir_redis_cluster}/${port}/redis-${port}.conf
done
;;
build)
# 創建容器配置並運行
for port in `seq 7000 7005`; do
docker run --name redis-${port} --net redis-cluster-net -d \
-p ${port}:${port} -p 1${port}:1${port} \
-v ${dir_redis_cluster}/${port}/data:/data \
-v ${dir_redis_cluster}/${port}/redis-${port}.conf:/usr/local/etc/redis/redis.conf redis \
redis-server /usr/local/etc/redis/redis.conf
done
;;
start | begin)
# 運行容器
for port in `seq 7000 7005`; do
docker start redis-${port}
done
;;
stop | end)
# 停止容器運行
for port in `seq 7000 7005`; do
docker stop redis-${port}
done
;;
rm)
# 刪除已有容器
for port in `seq 7000 7005`; do
docker rm redis-${port}
done
;;
restart)
# 重啟已有容器
for port in `seq 7000 7005`; do
docker restart redis-${port}
done
;;
destroy)
# 刪除集群目錄及配置
for port in `seq 7000 7005`; do
rm -rf ${dir_redis_cluster}/${port}
done
;;
*)
echo "Usage: ./build [create|build|start|stop|rm|restart|destroy]"
;;
esac