redis cluster集群搭建

redis 6.2

使用docker搭建redis cluster集群(3主3从)

所有的操作都在根目录~/Developer/docker-compose/redis-cluster-6.2执行

创建配置文件

为了方便,写了个shell脚本,懒人必备

createConfig.sh

for port in $(seq 6381 6386); 
do
    conf_dir=./${port}/conf
    conf_file=${conf_dir}/redis.conf
    log_dir=./${port}/logs
    if [ ! -d ${conf_dir} ]; then
        mkdir -p ${conf_dir}
    fi
    if [ ! -d ${log_dir} ]; then
        mkdir -p ${log_dir}
    fi
    if [ -f ${conf_file} ]; then
        rm -f ${conf_file}
    fi
    touch ${conf_file}
    cat  << EOF > ${conf_file}
bind 0.0.0.0
port ${port}
requirepass 123456
masterauth 123456
dir /data
logfile /logs/nodes-${port}.log
appendonly yes
cluster-enabled yes 
cluster-config-file nodes-${port}.conf
cluster-node-timeout 5000
cluster-announce-ip host.docker.internal
cluster-announce-port ${port}
cluster-announce-bus-port 1${port}
EOF
done

然后执行sh createConfig.sh即可。最终生成的文件如图所示

配置说明

# 允许其他机器访问redis服务
bind 0.0.0.0
# 连接端口
port 6381
# 密码
requirepass 123456
# 从节点需要配置主节点的密码, 不然主从同步时从节点无法从主节点同步到数据
masterauth 123456
# 数据根目录, 如rdb快照、aof文件、cluster-config-file指定的文件都在该目录下
dir /data
# 日志文件, 默认输出到控制台
logfile /logs/nodes-6381.log
# 开启aof持久化
appendonly yes
# 开启cluster集群模式
cluster-enabled yes
# 集群配置信息文件名, 记录了每个节点的地址、角色(master/slave)、slot等信息, 由redis自己生成, 位于数据目录下
cluster-config-file nodes-6381.conf
# 集群节点连接超时时间,每个节点都会检查其它节点是否挂了
cluster-node-timeout 5000
# docker所在的宿主机ip
cluster-announce-ip 192.168.2.102
# docker所在的宿主机映射端口
cluster-announce-port 6381
# docker所在的宿主机总线映射端口
cluster-announce-bus-port 16381

注:

  • daemonize不能设置为yes,否则容器将启动不了。

  • masterauth, 如果master节点设置了密码,slave节点配置文件必须指定该属性的值为master配置的密码,不然无法主从同步。

  • cluster-announce-ip、cluster-announce-port、cluster-announce-bus-port作用,如果不设置这几个字段,cluster-config-file指定的集群配置信息文件将会记录的是容器的ip,如果各个节点不在同一台宿主机中,那么各集群节点将无法通信。当然如果在同一宿主机且同一网络下部署集群,那么容器之间是可以通过ip访问的,也就是说集群节点可以相互通信,redis集群是可以正常工作的。但是这样会出现一个新问题,客户端连接redis集群时,返回的拓扑结构也是cluster-config-file配置文件里的ip,即容器ip(即便客户端指定的节点信息是宿主机ip也没用)。也就是说客户端若无法直接访问集群的容器ip,则不能连接redis集群

    测试现象:

    客户端配置

    spring:
      data:
        redis:
          cluster:
            # 使用宿主机ip
            nodes: 127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384,127.0.0.1:6385,127.0.0.1:6386
          password: 123456
          connect-timeout: 5000
          timeout: 30000
    

    集群部署信息

    部署在同一宿主机同一网络下,且未设置cluster-announce-ip、cluster-announce-port、cluster-announce-bus-port相关字段

    集群节点:172.19.0.101:6381 172.19.0.102:6382 172.19.0.103:6383 172.19.0.104:6384 172.19.0.105:6385 172.19.0.106:6386

    每个redis节点都会绑定端口到宿主机的对应端口上

    由于macos docker中,宿主机是不能访问容器的,将会报以下错误。

    connection timed out after 5000 ms: /172.19.0.102:6382
    connection timed out after 5000 ms: /172.19.0.103:6383
    connection timed out after 5000 ms: /172.19.0.101:6381
    connection timed out after 5000 ms: /172.19.0.105:6385
    connection timed out after 5000 ms: /172.19.0.106:6386
    connection timed out after 5000 ms: /172.19.0.104:6384
    

    由此可见,客户端连接时会使用cluster-config-file配置文件里的ip、port。

  • 集群节点之间是通过另外一个名为总线端口(bus-port)来通信,该端口为port+10000,因此为16381,宿主机映射端口时将宿主机的16381端口与容器的16381端口进行映射,所以cluster-announce-bus-port得值设置16381。这样各集群节点就可以通过宿主机ip+映射端口进行通信了。

  • 集群节点之间使用cluster-announce-ip:cluster-announce-bus-port通信,客户端连接集群使用cluster-announce-ip:cluster-announce-port通信。因此我们可以设置cluster-announce-ip的值为host.docker.internal,这样集群节点之间可以借助宿主机来通信,而客户端宿主机则可以配置host.docker.internal指向127.0.0.1,客户端也能连上集群了,这样子可以不用依赖宿主机具体的ip信息了,即便没有网络也能愉快的玩耍。

  • cluster-config-file内容示例

    拿第一行来说明

    ce30a10f22dfea5374588a5a34217d4053dea863:节点唯一标识。

    192.168.2.102:6381@16381:节点ip、port、bus-port,也就是cluster-announce-ip、cluster-announce-port、cluster-announce-bus-port配置的值。

    master: 该节点为master。

    0-5460: 该节点分配的hash slot,总共16384个。

    第二行的节点是slave节点,4d8bdde1b80182d3da1c8ac751ce495470a82d14代表master节点标识,然后没有hash slot信息。

    ce30a10f22dfea5374588a5a34217d4053dea863 192.168.2.102:6381@16381 master - 0 1687967066000 1 connected 0-5460
    c71b8b1d7ed8048a1c0794fa9eff89f02c527c30 192.168.2.102:6386@16386 slave 4d8bdde1b80182d3da1c8ac751ce495470a82d14 0 1687967067151 2 connected
    47b577cbb59fae528f10d7928755b41528097d1b 192.168.2.102:6385@16385 slave ce30a10f22dfea5374588a5a34217d4053dea863 0 1687967066147 1 connected
    5d17c4f2a3e2715b868e32b05d7c997fadaa2233 192.168.2.102:6384@16384 slave b6fa28612b4fb1f18cb9a3aec86d0363a4f01713 0 1687967065340 3 connected
    4d8bdde1b80182d3da1c8ac751ce495470a82d14 192.168.2.102:6382@16382 myself,master - 0 1687967065000 2 connected 5461-10922
    b6fa28612b4fb1f18cb9a3aec86d0363a4f01713 192.168.2.102:6383@16383 master - 0 1687967067000 3 connected 10923-16383
    vars currentEpoch 6 lastVoteEpoch 0
    

编写docker-compose.yml文件

编写docker-compose文件来一键启动6个redis节点

services:
  redis-6381:
    image: redis:6.2
    container_name: redis-6381
    ports:
      - 6381:6381
      - 16381:16381
    volumes:
      - ./6381/conf/redis.conf:/etc/redis.conf
      - ./6381/data:/data
      - ./6381/logs:/logs
    command: ["redis-server", "/etc/redis.conf"]
    environment:
      - TZ=Asia/Shanghai
    networks:
      redis-cluster:
        aliases:
          - redis-6381
        ipv4_address: 172.19.0.101
          
  redis-6382:
    image: redis:6.2
    container_name: redis-6382
    ports:
      - 6382:6382
      - 16382:16382
    volumes:
      - ./6382/conf/redis.conf:/etc/redis.conf
      - ./6382/data:/data
      - ./6382/logs:/logs
    command: ["redis-server", "/etc/redis.conf"]
    environment:
      - TZ=Asia/Shanghai
    networks:
      redis-cluster:
        aliases:
          - redis-6382
        ipv4_address: 172.19.0.102
          
  redis-6383:
    image: redis:6.2
    container_name: redis-6383
    ports:
      - 6383:6383
      - 16383:16383
    volumes:
      - ./6383/conf/redis.conf:/etc/redis.conf
      - ./6383/data:/data
      - ./6383/logs:/logs
    command: ["redis-server", "/etc/redis.conf"]
    environment:
      - TZ=Asia/Shanghai
    networks:
      redis-cluster:
        aliases:
          - redis-6383
        ipv4_address: 172.19.0.103
          
  redis-6384:
    image: redis:6.2
    container_name: redis-6384
    ports:
      - 6384:6384
      - 16384:16384
    volumes:
      - ./6384/conf/redis.conf:/etc/redis.conf
      - ./6384/data:/data
      - ./6384/logs:/logs
    command: ["redis-server", "/etc/redis.conf"]
    environment:
      - TZ=Asia/Shanghai
    networks:
      redis-cluster:
        aliases:
          - redis-6384
        ipv4_address: 172.19.0.104
          
  redis-6385:
    image: redis:6.2
    container_name: redis-6385
    ports:
      - 6385:6385
      - 16385:16385
    volumes:
      - ./6385/conf/redis.conf:/etc/redis.conf
      - ./6385/data:/data
      - ./6385/logs:/logs
    command: ["redis-server", "/etc/redis.conf"]
    environment:
      - TZ=Asia/Shanghai
    networks:
      redis-cluster:
        aliases:
          - redis-6385
        ipv4_address: 172.19.0.105
          
  redis-6386:
    image: redis:6.2
    container_name: redis-6386
    ports:
      - 6386:6386
      - 16386:16386
    volumes:
      - ./6386/conf/redis.conf:/etc/redis.conf
      - ./6386/data:/data
      - ./6386/logs:/logs
    command: ["redis-server", "/etc/redis.conf"]
    environment:
      - TZ=Asia/Shanghai
    networks:
      redis-cluster:
        aliases:
          - redis-6386
        ipv4_address: 172.19.0.106

networks:
  redis-cluster:
    name: redis-cluster
    driver: bridge
    ipam:
      config:
        - subnet: 172.19.0.0/16
          gateway: 172.19.0.1

启动节点

# 启动
docker compose run -d
# 查看容器
docker compose ps

将各节点加入到集群中

上面还只是启动了6个redis节点,没有加入到共同的集群中。

随意进入一个容器中

docker compose exec -it redis-6381 /bin/bash

使用下面命令创建集群

redis-cli -a 123456 --cluster create 172.19.0.101:6381 172.19.0.102:6382 172.19.0.103:6383 172.19.0.104:6384 172.19.0.105:6385 172.19.0.106:6386 --cluster-replicas 1

其中--cluster-replicas 1表示每个master只有1个slave节点。

查看集群信息

连接任意个节点redis-cli -p 6381,执行以下命令可查看集群信息

cluster info

结果

# 集群状态
cluster_state:ok
# 总的hash slot数量
cluster_slots_assigned:16384
# 正常的hash slot数量
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
# 总共节点数
cluster_known_nodes:6
# 分片大小,因为只有3个master,所以为3
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1237
cluster_stats_messages_pong_sent:1285
cluster_stats_messages_sent:2522
cluster_stats_messages_ping_received:1280
cluster_stats_messages_pong_received:1237
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:2522

查看节点信息

cluster nodes

结果和cluster-config-file指定的文件内容一样

3369a4635ddca9c23247927b80f52b53cf6e98df 192.168.2.102:6386@16386 slave febb65499a03fb25184a6a1fc90b46e295ff4d97 0 1688036065000 3 connected
4f20c39196e0655ef3ce4ef51ed20489cba3e5f0 192.168.2.102:6381@16381 myself,master - 0 1688036066000 1 connected 0-5460
febb65499a03fb25184a6a1fc90b46e295ff4d97 192.168.2.102:6383@16383 master - 0 1688036066485 3 connected 10923-16383
e13bc519b106c9a50df89091a28fc4663af4c579 192.168.2.102:6382@16382 master - 0 1688036066588 2 connected 5461-10922
128564cd3bab4205b6db0a67871d003f87c744a3 192.168.2.102:6384@16384 slave 4f20c39196e0655ef3ce4ef51ed20489cba3e5f0 0 1688036065487 1 connected
8d838e07718f8181d73993f0d0509632ce6f95cb 192.168.2.102:6385@16385 slave e13bc519b106c9a50df89091a28fc4663af4c579 0 1688036065000 2 connected
vars currentEpoch 6 lastVoteEpoch 0

查看hash slot分布情况

cluster slots

结果

代表0-5460属于192.168.2.102:6381节点,192.168.2.102:6384是192.168.2.102:6381从节点

5461-10922属于192.168.2.102:6382节点,192.168.2.102:6385是192.168.2.102:6382从节点

10923-16383属于192.168.2.102:6383节点,192.168.2.102:6386是192.168.2.102:6383从节点

1) 1) (integer) 0
   2) (integer) 5460
   3) 1) "192.168.2.102"
      2) (integer) 6381
      3) "4f20c39196e0655ef3ce4ef51ed20489cba3e5f0"
   4) 1) "192.168.2.102"
      2) (integer) 6384
      3) "128564cd3bab4205b6db0a67871d003f87c744a3"
2) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "192.168.2.102"
      2) (integer) 6382
      3) "e13bc519b106c9a50df89091a28fc4663af4c579"
   4) 1) "192.168.2.102"
      2) (integer) 6385
      3) "8d838e07718f8181d73993f0d0509632ce6f95cb"
3) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "192.168.2.102"
      2) (integer) 6383
      3) "febb65499a03fb25184a6a1fc90b46e295ff4d97"
   4) 1) "192.168.2.102"
      2) (integer) 6386
      3) "3369a4635ddca9c23247927b80f52b53cf6e98df"

验证

验证主从是否同步

接下来,往redis中添加数据

还是任意连接一个master节点,因为slave节点不允许新增数据。

进入容器内部

docker compose exec -it redis-6381 /bin/bash

连接redis

redis-cli -p 6381
auth 123456

新增数据

set username wastonl

结果

(error) MOVED 14315 192.168.2.102:6383

表明redis经过hash计算,username这个key需要存放到192.168.2.102:6383节点中,因此连接到192.168.2.102:6383节点再进行该操作。

redis-cli -p 6383
auth 123456
set username wastonl

结果就ok了。

然后再去192.168.2.102:6383节点的从节点去查询数据,看看数据数据是否被正确同步到从节点中,可以通过cluster nodes查看从节点192.168.2.102:6386。

get username

结果

(error) MOVED 14315 192.168.2.102:6383

Redis Cluster集群中的从节点,官方默认设置的是不分担读请求的、只作备份和故障转移用,当有请求读向从节点时,会被重定向到对应的主节点来处理。

需要使用readonly命令才能读取数据,断开连接后,该命令会失效,需要重新使用readonly才能读取数据。

readonly
get username

结果

"wastonl"

验证是否故障转移

如果master挂了,slave节点会被选举成新的master来工作,掌管原来master分配的hash slot。

停掉6381节点(master)

docker compose stop redis-6381

连接6382节点查询集群信息

cluster info

结果

cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:7
cluster_my_epoch:2
cluster_stats_messages_ping_sent:1776
cluster_stats_messages_pong_sent:1832
cluster_stats_messages_meet_sent:1
cluster_stats_messages_fail_sent:4
cluster_stats_messages_auth-ack_sent:1
cluster_stats_messages_sent:3614
cluster_stats_messages_ping_received:1832
cluster_stats_messages_pong_received:1777
cluster_stats_messages_fail_received:1
cluster_stats_messages_auth-req_received:1
cluster_stats_messages_received:3611

可以看到集群状态还是正常的

cluster nodes

结果

28564cd3bab4205b6db0a67871d003f87c744a3 192.168.2.102:6384@16384 master - 0 1688037075078 7 connected 0-5460
8d838e07718f8181d73993f0d0509632ce6f95cb 192.168.2.102:6385@16385 slave e13bc519b106c9a50df89091a28fc4663af4c579 0 1688037073640 2 connected
3369a4635ddca9c23247927b80f52b53cf6e98df 192.168.2.102:6386@16386 slave febb65499a03fb25184a6a1fc90b46e295ff4d97 0 1688037073000 3 connected
e13bc519b106c9a50df89091a28fc4663af4c579 192.168.2.102:6382@16382 myself,master - 0 1688037073000 2 connected 5461-10922
febb65499a03fb25184a6a1fc90b46e295ff4d97 192.168.2.102:6383@16383 master - 0 1688037074666 3 connected 10923-16383
4f20c39196e0655ef3ce4ef51ed20489cba3e5f0 192.168.2.102:6381@16381 master,fail - 1688036983438 1688036982426 1 disconnected

可以看到6381节点的状态是fail,而6381节点的从节点6384变成了新的主节点,并且hash slot还是0-5460。

如果重新启动6381节点,会看到6381节点变成了6384节点的从节点了。

posted on 2023-06-29 19:24  wastonl  阅读(960)  评论(0编辑  收藏  举报