[Redis] 手動搭建標準6節點Redis集羣(docker)

準備

環境配置

docker redis鏡像

# docker 拉取redis鏡像
docker pull redis
# redis 鏡像詳情
docker inspect redis

redis版本爲 5.0.4 redis鏡像詳情html

docker 集羣網絡

# 建立屬於redis的集羣網絡
docker network create redis-cluster-net

網關Gateway: 172.18.0.1 集羣網絡情況java

集羣掛載目錄

  1. 打算開啓6個節點, 3對主從節點搭建集羣
  2. 開放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

執行效果圖

節點7000的配置文件

配置文件模板

# 基本配置
## 開放端口
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

build

  • 使用配置文件啓動 使用配置文件啓動
  • 查看各節點所分配到的ip是否符合 查看各節點所分配到的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}

分配slots

分配結果

測試

redis-cli

使用redis命令行工具測試集羣

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"));
    }
}

Jedis測試結果

遭遇問題

問題一 ERR This instance has cluster support disabled

進入節點 輸入cluster info 查看該節點是否開啓集羣功能, 報錯node

探查緣由

  1. redis-cli 使用config get *命令查看配置信息
  2. docker inspect [id/name]查看容器內部配置信息

問題二 Fatal error, can't open config file

沒法打開配置文件git

探查緣由

  1. 不是權限問題
  2. 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查看日誌也沒什麼問題redis

探查問題

  • 開始覺得本身的啓動方式有誤
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

發現配置文件都配置上去了, 能夠查看內容docker

  • 在容器內部使用bash啓動redis-server

redis-server [] 啓動不了 說是7000端口被佔用了 ???等等 容器內部7000端口被啓用了?shell

  • 配置文件的port是給容器內部使用的
  1. 將配置文件更改成port 6379 便可以使用redis-cli默認打開redis命令行
  2. 配置文件爲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

探查問題

  • 容器網絡問題
  1. 能夠直接使用host解決

--net=host 告訴Docker不要將容器網絡放到隔離的命名空間中,即不要容器化容器內的網絡。此時容器使用本地主機的網絡,它擁有徹底的本地主機接口訪問權限。容器進程能夠跟主機其它 root 進程同樣能夠打開低範圍的端口,能夠訪問本地網絡服務好比 D-bus,還可讓容器作一些影響整個主機系統的事情,好比重啓主機。所以使用這個選項的時候要很是當心。若是進一步的使用 --privileged=true,容器會被容許直接配置主機的網絡堆棧。segmentfault

  1. 也可使用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-netbash

    • 在啓動容器時, 添加 -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
相關文章
相關標籤/搜索