:::info 注:本文基于Redis-6.2.4版本
因为redis5.0开始使用 redis-cli 作为创建集群的命令,使用c语言实现,不再使用ruby语言(所以Linux环境中也不用再安装Ruby) :::

Redis Cluster

在前面的文章中介绍过了redis的主从和哨兵两种集群方案,redis从3.0版本开始引入了redis-cluster(集群)。从主从-哨兵-集群可以看到redis的不断完善;主从复制是最简单的节点同步方案无法主从自动故障转移。哨兵可以同时管理多个主从同步方案同时也可以处理主从自动故障转移,通过配置多个哨兵节点可以解决单点网络故障问题,但是单个节点的性能压力问题无法解决。集群解决了前面两个方案的所有问题。

  • Redis-Cluster采用无中心结构,每个节点都和其它节点通过互ping保持连接,每个节点保存整个集群的状态信息,可以通过连接任意节点读取或者写入数据(甚至是没有数据的空节点)。
  • 只有当集群中的大多数节点同时fail整个集群才fail。
  • 整个集群有16384个slot,当需要在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中。读取一个key时也是相同的算法。
  • 当主节点fail时从节点会升级为主节点,fail的主节点online之后自动变成了从节点。

    架构图

    Redis Cluster集群模式 - 图1

    Redis为什么哈希槽的数量固定为16384?

    https://github.com/antirez/redis/issues/2576

总结一下:

  1. redis的一个节点的心跳信息中需要携带该节点的所有配置信息,而16K大小的槽数量所需要耗费的内存为2K,但如果使用65K个槽,这部分空间将达到8K,心跳信息就会很庞大。
  2. Redis集群中主节点的数量基本不可能超过1000个。
  3. Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话,bitmap的压缩率就很低,所以N表示节点数,如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。而16K个槽当主节点为1000的时候,是刚好比较合理的,既保证了每个节点有足够的哈希槽,又可以很好的利用bitmap。
  4. 选取了16384是因为crc16会输出16bit的结果,可以看作是一个分布在0-2^16-1之间的数,redis的作者测试发现这个数对2^14求模的会将key在0-2^14-1之间分布得很均匀,因此选了这个值。

    环境搭建

    Redis Cluster集群模式 - 图2

    下载

    还是和搭建单机版一样先下载安装包:Redis安装单机版

    复制配置文件

    1. [root@redis-master redis-6.2.4]# mkdir cluster-conf
    2. [root@redis-master redis-6.2.4]# cp redis.conf cluster-conf/redis-cluster-1.conf
    3. [root@redis-master redis-6.2.4]# cp redis.conf cluster-conf/redis-cluster-2.conf
    4. [root@redis-master redis-6.2.4]# cp redis.conf cluster-conf/redis-cluster-3.conf
    5. [root@redis-master redis-6.2.4]# cp redis.conf cluster-conf/redis-cluster-4.conf
    6. [root@redis-master redis-6.2.4]# cp redis.conf cluster-conf/redis-cluster-5.conf
    7. [root@redis-master redis-6.2.4]# cp redis.conf cluster-conf/redis-cluster-6.conf

    修改配置文件

    依次将6个文件都修改一下,实际上可以先修改一个再复制哈哈 ```shell

    后台启动

    daemonize yes

    修改端口号,16379 16380 16381 16382 16383 16384

    port 16379

开启cluster,去掉注释

cluster-enabled yes

因为我是同一台机器上跑的,为了区分进程 16379 16380 16381 16382 16383 16384

pidfile “/var/run/redis_16379.pid”

存储redis集群配置信息,是系统自动生成 nodes-16379.conf nodes-16380.conf nodes-16381.conf nodes-16382.conf nodes-16383.conf nodes-16384.conf

cluster-config-file “/usr/local/redis-6.2.4/cluster-nodes/nodes-16379.conf”

节点通信时间

cluster-node-timeout 15000

持久化方式

appendonly yes

绑定ip

bind 0.0.0.0

认证密码

requirepass anin

  1. <a name="CrRQC"></a>
  2. ### 启动redis
  3. 这里写了一个启动脚本方便一点
  4. ```shell
  5. [root@redis-master redis-6.2.4]# vim start-cluster-all.sh
  6. cd src
  7. redis-server ../cluster-conf/redis-cluster-1.conf
  8. redis-server ../cluster-conf/redis-cluster-2.conf
  9. redis-server ../cluster-conf/redis-cluster-3.conf
  10. redis-server ../cluster-conf/redis-cluster-4.conf
  11. redis-server ../cluster-conf/redis-cluster-5.conf
  12. redis-server ../cluster-conf/redis-cluster-6.conf
  13. echo "OK"
  14. ps -ef|grep redis
  15. [root@redis-master redis-6.2.4]# chmod 777 start-cluster-all.sh
  16. [root@redis-master redis-6.2.4]# ./start-cluster-all.sh
  17. OK
  18. root 1484 1 0 17:14 ? 00:00:00 redis-server 0.0.0.0:16379 [cluster]
  19. root 1490 1 0 17:14 ? 00:00:00 redis-server 0.0.0.0:16380 [cluster]
  20. root 1492 1 0 17:14 ? 00:00:00 redis-server 0.0.0.0:16381 [cluster]
  21. root 1502 1 0 17:14 ? 00:00:00 redis-server 0.0.0.0:16382 [cluster]
  22. root 1504 1 0 17:14 ? 00:00:00 redis-server 0.0.0.0:16383 [cluster]
  23. root 1514 1 0 17:14 ? 00:00:00 redis-server 0.0.0.0:16384 [cluster]
  24. root 1520 1394 0 17:14 pts/0 00:00:00 grep --color=auto redis

创建集群

  1. [root@redis-master redis-6.2.4]# redis-cli --cluster create 127.0.0.1:16379 127.0.0.1:16380 127.0.0.1:16381 127.0.0.1:16382 127.0.0.1:16383 127.0.0.1:16384 -a anin --cluster-replicas 1
  2. Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
  3. >>> Performing hash slots allocation on 6 nodes...
  4. Master[0] -> Slots 0 - 5460
  5. Master[1] -> Slots 5461 - 10922
  6. Master[2] -> Slots 10923 - 16383
  7. Adding replica 127.0.0.1:16383 to 127.0.0.1:16379
  8. Adding replica 127.0.0.1:16384 to 127.0.0.1:16380
  9. Adding replica 127.0.0.1:16382 to 127.0.0.1:16381
  10. >>> Trying to optimize slaves allocation for anti-affinity
  11. [WARNING] Some slaves are in the same host as their master
  12. M: d3918d2cf9ce360132ce0403991a6486488cb90c 127.0.0.1:16379
  13. slots:[0-5460] (5461 slots) master
  14. M: a86d513d5a7d2e59d8ec4af3866438b3872c6f29 127.0.0.1:16380
  15. slots:[5461-10922] (5462 slots) master
  16. M: d75da7b006ae8f832529c04364af8bf20809d030 127.0.0.1:16381
  17. slots:[10923-16383] (5461 slots) master
  18. S: f55cff3cb03ebc3cdb0995d3f52f828da60a1d14 127.0.0.1:16382
  19. replicates d3918d2cf9ce360132ce0403991a6486488cb90c
  20. S: d45254a357654dbe8335696649061db0eb573a96 127.0.0.1:16383
  21. replicates a86d513d5a7d2e59d8ec4af3866438b3872c6f29
  22. S: b60cea5ec2997ce5a7b6af105bcba5620b321120 127.0.0.1:16384
  23. replicates d75da7b006ae8f832529c04364af8bf20809d030
  24. Can I set the above configuration? (type 'yes' to accept):

打印出一份预想中的配置给你看, 如果觉得没问题的话, 就可以输入 yes ,就会将这份配置应用到集群当中,让各个节点开始互相通讯,最后可以得到如下信息:

  1. Can I set the above configuration? (type 'yes' to accept): yes
  2. >>> Nodes configuration updated
  3. >>> Assign a different config epoch to each node
  4. >>> Sending CLUSTER MEET messages to join the cluster
  5. Waiting for the cluster to join
  6. >>> Performing Cluster Check (using node 127.0.0.1:16379)
  7. M: d3918d2cf9ce360132ce0403991a6486488cb90c 127.0.0.1:16379
  8. slots:[0-5460] (5461 slots) master
  9. 1 additional replica(s)
  10. M: a86d513d5a7d2e59d8ec4af3866438b3872c6f29 127.0.0.1:16380
  11. slots:[5461-10922] (5462 slots) master
  12. 1 additional replica(s)
  13. S: f55cff3cb03ebc3cdb0995d3f52f828da60a1d14 127.0.0.1:16382
  14. slots: (0 slots) slave
  15. replicates d3918d2cf9ce360132ce0403991a6486488cb90c
  16. S: d45254a357654dbe8335696649061db0eb573a96 127.0.0.1:16383
  17. slots: (0 slots) slave
  18. replicates a86d513d5a7d2e59d8ec4af3866438b3872c6f29
  19. S: b60cea5ec2997ce5a7b6af105bcba5620b321120 127.0.0.1:16384
  20. slots: (0 slots) slave
  21. replicates d75da7b006ae8f832529c04364af8bf20809d030
  22. M: d75da7b006ae8f832529c04364af8bf20809d030 127.0.0.1:16381
  23. slots:[10923-16383] (5461 slots) master
  24. 1 additional replica(s)
  25. [OK] All nodes agree about slots configuration.
  26. >>> Check for open slots...
  27. >>> Check slots coverage...
  28. [OK] All 16384 slots covered.

可以按到OK了

查看集群状态

  1. [root@redis-master redis-6.2.4]# src/redis-cli -h 127.0.0.1 -p 16379 -a anin cluster info
  2. Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
  3. cluster_state:ok
  4. cluster_slots_assigned:16384
  5. cluster_slots_ok:16384
  6. cluster_slots_pfail:0
  7. cluster_slots_fail:0
  8. cluster_known_nodes:6
  9. cluster_size:3
  10. cluster_current_epoch:6
  11. cluster_my_epoch:1
  12. cluster_stats_messages_ping_sent:134
  13. cluster_stats_messages_pong_sent:146
  14. cluster_stats_messages_sent:280
  15. cluster_stats_messages_ping_received:141
  16. cluster_stats_messages_pong_received:134
  17. cluster_stats_messages_meet_received:5
  18. cluster_stats_messages_received:280

查看节点信息

  1. [root@redis-master redis-6.2.4]# src/redis-cli -h 127.0.0.1 -p 16379 -a anin cluster nodes
  2. Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
  3. a86d513d5a7d2e59d8ec4af3866438b3872c6f29 127.0.0.1:16380@26380 master - 0 1626679011049 2 connected 5461-10922
  4. f55cff3cb03ebc3cdb0995d3f52f828da60a1d14 127.0.0.1:16382@26382 slave d3918d2cf9ce360132ce0403991a6486488cb90c 0 1626679012052 1 connected
  5. d3918d2cf9ce360132ce0403991a6486488cb90c 127.0.0.1:16379@26379 myself,master - 0 1626679009000 1 connected 0-5460
  6. d45254a357654dbe8335696649061db0eb573a96 127.0.0.1:16383@26383 slave a86d513d5a7d2e59d8ec4af3866438b3872c6f29 0 1626679010047 2 connected
  7. b60cea5ec2997ce5a7b6af105bcba5620b321120 127.0.0.1:16384@26384 slave d75da7b006ae8f832529c04364af8bf20809d030 0 1626679011000 3 connected
  8. d75da7b006ae8f832529c04364af8bf20809d030 127.0.0.1:16381@26381 master - 0 1626679009045 3 connected 10923-16383

集群关闭

集群关闭只需要关闭所以redis节点就可以了

  1. [root@redis-master redis-6.2.4]# cat stop-cluster-all-sh
  2. cd src
  3. redis-cli -p 16379 -a anin shutdown
  4. redis-cli -p 16380 -a anin shutdown
  5. redis-cli -p 16381 -a anin shutdown
  6. redis-cli -p 16382 -a anin shutdown
  7. redis-cli -p 16383 -a anin shutdown
  8. redis-cli -p 16384 -a anin shutdown
  9. echo 'OK'
  10. ps -ef|grep redis

集群重启

和上面的集群关闭一样,只需要全部再启动就可以了

  1. [root@redis-master redis-6.2.4]# cat start-cluster-all.sh
  2. cd src
  3. redis-server ../cluster-conf/redis-cluster-1.conf
  4. redis-server ../cluster-conf/redis-cluster-2.conf
  5. redis-server ../cluster-conf/redis-cluster-3.conf
  6. redis-server ../cluster-conf/redis-cluster-4.conf
  7. redis-server ../cluster-conf/redis-cluster-5.conf
  8. redis-server ../cluster-conf/redis-cluster-6.conf
  9. echo "OK"
  10. ps -ef|grep redis

删除集群

关闭所有redis节点,然后删除redis集群配置,看情况需不需要删除redis数据。
redis集群的配置就在我们刚才上面配置的地址。

  1. [root@redis-master redis-6.2.4]# ll cluster-nodes/
  2. 总用量 24
  3. -rw-r--r--. 1 root root 787 7 19 15:35 nodes-16379.conf
  4. -rw-r--r--. 1 root root 787 7 19 15:35 nodes-16380.conf
  5. -rw-r--r--. 1 root root 787 7 19 15:35 nodes-16381.conf
  6. -rw-r--r--. 1 root root 787 7 19 15:35 nodes-16382.conf
  7. -rw-r--r--. 1 root root 787 7 19 15:34 nodes-16383.conf
  8. -rw-r--r--. 1 root root 787 7 19 15:35 nodes-16384.conf

遇到的问题

数据节点不为空

  1. [ERR] Node 127.0.0.1:16379 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.

解决办法:
把每个库都清掉

  1. flushdb

提示我们不是所有的slot都被节点覆盖到

  1. [ERR] Not all 16384 slots are covered by nodes.

解决办法:
官方的建议是使用fix修复

  1. [root@redis-master src]# redis-cli --cluster fix