zoukankan      html  css  js  c++  java
  • [Redis] 手动搭建标准6节点Redis集群(docker)

    准备

    环境配置

    docker redis镜像

    # docker 拉取redis镜像
    docker pull redis
    # redis 镜像详情
    docker inspect redis
    

    redis版本为 5.0.4
    redis镜像详情

    docker 集群网络

    # 创建属于redis的集群网络
    docker network create redis-cluster-net
    

    网关Gateway: 172.18.0.1
    集群网络状况

    集群挂载目录

    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 查看该节点是否开启集群功能, 报错

    探查原因

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

    问题二 Fatal error, can't open config file

    无法打开配置文件

    探查原因

    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查看日志也没什么问题

    探查问题

    • 开始以为自己的启动方式有误
    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是给容器内部使用的
    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,容器会被允许直接配置主机的网络堆栈。

    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-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
    
  • 相关阅读:
    【原】【Git】EGit强制覆盖本地文件
    【EGit】The current branch is not configured for pull No value for key branch.master.merge found in config
    【转】【Egit】如何将eclipse中的项目上传至Git
    参加SAP VT项目有感
    2013_12_30 纪念
    2013 12 25 圣诞日
    gin系列-中间件
    gin系列- 路由及路由组
    gin系列-重定向
    gin系列-文件上传
  • 原文地址:https://www.cnblogs.com/slowbirdoflsh/p/11633113.html
Copyright © 2011-2022 走看看