Redis集群模式

Redis Cluster概念原理与部署

本质是分布式缓存;

解决“大量”缓存问题,单机内存不足,需要随时扩容;

使用“分片”机制解决,(类似Raid 10),将数据存储在不同的主机上,使用网络连接,拆分数据与查找数据使用hash算法进行计算,查找;

Redis:key-value(取值0-16383)

集群介绍

集群概念

sentinel模式基本可以满足一般生产的需求,具备高可用性。但是当数据量过大到一台服务器存放不下的情况时,主从模式或sentinel模式就不能满足需求了,这个时候需要对存储的数据进行分片,将数据存储到多个Redis实例中。cluster模式的出现就是为了解决单机Redis容量有限的问题,将Redis的数据根据一定的规则分配到多台机器。

什么是集群模式

Redis 的哨兵和主从模式基本已经可以实现高可用和读写分离 ,但是在这种模式下每台 Redis 服务器都存储相同的数据,浪费内存空间,所以在redis上加入了 Cluster 集群模式,实现了 Redis 的分布式存储,也就是说Redis 节点上存储不同的内容。

集群模式特点

所有的节点都是一主一从(也可以是一主多从),其中从节点不提供服务,仅作为备用

不支持同时处理多个key(如MSET/MGET),因为redis需要把key均匀分布在各个节点上,并发量很高的情况下同时创建key-value会降低性能并导致不可预测的行为

支持在线增加、删除节点

客户端可以连接任何一个主节点进行读写

集群工作方式

数据存取工作方式

在 Redis 的每一个节点上,都有这么两个东西,一个是插槽(slot),一个是cluster。

插槽的取值范围是:0-16383。cluster,可以理解为是一个集群管理的插件。

当我们的存取 Key的时候,Redis 会根据算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。

集群工作方式

为了保证高可用,redis集群模式引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。

那么如何发现主节点宕机?当其它主节点ping一个主节点C时,如果半数以上的主节点与C通信超时,那么认为主节点C宕机了。如果主节点C和它的从节点C1都宕机了,那么该集群就无法再提供服务了。

集群模式的搭建

搭建前的准备

  • 集群搭建:

    • 方案一:测试环境或模拟环境可以,1-3节,点搭建测试

    • 方案二:生产环境初创项目最小可用,6节点,搭建3主3从满足高可用的最低成本方案

    • 方案三:中等规模业务,9-12节点,提升写入吞吐量,为未来扩展留出空间

    • 方案四:大规模高并发系统,15+节点,支撑极高的读写压力,实现更强的扩展性

集群搭建(3节点)

第一台机器(192.168.7.91)

 # 切换目录
 cd /usr/local/redis
 ​
 # 创建文件
 mkdir -p redis-cluster/{7001,7004}
 ​
 # 创建数据目录
 mkdir -p /usr/local/redis/data/{7001,7004}
 ​
 # 复制配置文件
 cp etc/redis.conf  redis-cluster/7001/redis.conf
 cp etc/redis.conf  redis-cluster/7004/redis.conf
 ​
 # 修改7001配置
 vim redis-cluster/7001/redis.conf
 ​
 # 编辑一下内容
 daemonize yes
 pidfile /var/run/redis_7001.pid
 port 7001
 bind 192.168.7.91
 protected-mode no
 dir /usr/local/redis/data/7001
 logfile /usr/local/redis/data/7001/redis.log
 appendonly yes
 cluster-enabled yes
 cluster-config-file nodes-7001.conf
 cluster-node-timeout 5000
 appendfsync everysec
 cluster-migration-barrier 1
 cluster-require-full-coverage yes
 maxmemory 4gb
 maxmemory-policy allkeys-lru
 ​
 ​
 # 修改7004配置
 vim redis-cluster/7004/redis.conf
 ​
 # 编辑一下内容
 daemonize yes
 pidfile /var/run/redis_7004.pid
 port 7004
 bind 192.168.7.91
 protected-mode no
 dir /usr/local/redis/data/7004
 logfile /usr/local/redis/data/7004/redis.log
 appendonly yes
 cluster-enabled yes
 cluster-config-file nodes-7004.conf
 cluster-node-timeout 5000
 appendfsync everysec
 cluster-migration-barrier 1
 cluster-require-full-coverage yes
 maxmemory 4gb
 maxmemory-policy allkeys-lru
 ​
 # 启动7001
 redis-server /usr/local/redis/redis-cluster/7001/redis.conf
 # 启动7004
 redis-server /usr/local/redis/redis-cluster/7004/redis.conf
 ​
 # 检查启动状态
 ps -ef | grep redis

第二台机器(192.168.7.92)

 # 切换目录
 cd /usr/local/redis
 ​
 # 创建文件
 mkdir -p redis-cluster/{7002,7005}
 ​
 # 创建数据目录
 mkdir -p /usr/local/redis/data/{7002,7005}
 ​
 # 复制配置文件
 cp etc/redis.conf  redis-cluster/7002/redis.conf
 cp etc/redis.conf  redis-cluster/7005/redis.conf
 ​
 # 修改7002配置
 vim redis-cluster/7002/redis.conf
 ​
 # 编辑一下内容
 daemonize yes
 pidfile /var/run/redis_7002.pid
 port 7002
 bind 192.168.7.92
 protected-mode no
 dir /usr/local/redis/data/7002
 logfile /usr/local/redis/data/7002/redis.log
 appendonly yes
 cluster-enabled yes
 cluster-config-file nodes-7002.conf
 cluster-node-timeout 5000
 appendfsync everysec
 cluster-migration-barrier 1
 cluster-require-full-coverage yes
 maxmemory 4gb
 maxmemory-policy allkeys-lru
 ​
 ​
 # 修改7005配置
 vim redis-cluster/7005/redis.conf
 ​
 # 编辑一下内容
 daemonize yes
 pidfile /var/run/redis_7005.pid
 port 7005
 bind 192.168.7.92
 protected-mode no
 dir /usr/local/redis/data/7005
 logfile /usr/local/redis/data/7005/redis.log
 appendonly yes
 cluster-enabled yes
 cluster-config-file nodes-7005.conf
 cluster-node-timeout 5000
 appendfsync everysec
 cluster-migration-barrier 1
 cluster-require-full-coverage yes
 maxmemory 4gb
 maxmemory-policy allkeys-lru
 ​
 # 启动7002
 redis-server /usr/local/redis/redis-cluster/7002/redis.conf
 # 启动7005
 redis-server /usr/local/redis/redis-cluster/7005/redis.conf
 ​
 # 检查启动状态
 ps -ef | grep redis

第三台机器(192.168.7.93)

 # 切换目录
 cd /usr/local/redis
 ​
 # 创建文件
 mkdir -p redis-cluster/{7003,7006}
 ​
 # 创建数据目录
 mkdir -p /usr/local/redis/data/{7003,7006}
 ​
 # 复制配置文件
 cp etc/redis.conf  redis-cluster/7003/redis.conf
 cp etc/redis.conf  redis-cluster/7006/redis.conf
 ​
 # 修改7003配置
 vim redis-cluster/7003/redis.conf
 ​
 # 编辑一下内容
 daemonize yes
 pidfile /var/run/redis_7003.pid
 port 7003
 bind 192.168.7.93
 protected-mode no
 dir /usr/local/redis/data/7003
 logfile /usr/local/redis/data/7003/redis.log
 appendonly yes
 cluster-enabled yes
 cluster-config-file nodes-7003.conf
 cluster-node-timeout 5000
 appendfsync everysec
 cluster-migration-barrier 1
 cluster-require-full-coverage yes
 maxmemory 4gb
 maxmemory-policy allkeys-lru
 ​
 ​
 # 修改7006配置
 vim redis-cluster/7006/redis.conf
 ​
 # 编辑一下内容
 daemonize yes
 pidfile /var/run/redis_7006.pid
 port 7006
 bind 192.168.7.93
 protected-mode no
 dir /usr/local/redis/data/7006
 logfile /usr/local/redis/data/7006/redis.log
 appendonly yes
 cluster-enabled yes
 cluster-config-file nodes-7006.conf
 cluster-node-timeout 5000
 appendfsync everysec
 cluster-migration-barrier 1
 cluster-require-full-coverage yes
 maxmemory 4gb
 maxmemory-policy allkeys-lru
 ​
 # 启动7003
 redis-server /usr/local/redis/redis-cluster/7003/redis.conf
 # 启动7006
 redis-server /usr/local/redis/redis-cluster/7006/redis.conf
 ​
 # 检查启动状态
 ps -ef | grep redis

创建集群(在任意一台机器执行,如192.168.7.91)

关键点:确保所有6个节点都已启动,然后在任意一台机器上执行创建命令。

 # 创建集群
 redis-cli --cluster create \
   192.168.7.91:7001 \
   192.168.7.92:7002 \
   192.168.7.93:7003 \
   192.168.7.91:7004 \
   192.168.7.92:7005 \
   192.168.7.93:7006 \
   --cluster-replicas 1

验证集群

6.1 查看集群节点信息

 # 查看节点信息
 redis-cli -c -h 192.168.7.91 -p 7001
 192.168.7.91:7001> cluster nodes

查看集群整体状态

 192.168.7.91:7001> 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:6
 cluster_my_epoch:1
 cluster_stats_messages_ping_sent:505
 cluster_stats_messages_pong_sent:501
 cluster_stats_messages_sent:1006
 cluster_stats_messages_ping_received:496
 cluster_stats_messages_pong_received:501
 cluster_stats_messages_meet_received:5
 cluster_stats_messages_received:1002

测试数据读写(自动跳转)

 # 登录客户端操作
 redis-cli -c -h 192.168.7.91 -p 7001
 ​
 # 写入数据(会自动跳转到对应的主节点)
 192.168.7.91:7001> set name zhangsan
 -> Redirected to slot [5798] located at 192.168.7.92:7002
 OK
 ​
 192.168.7.92:7002> get name
 "zhangsan"
 ​
 192.168.7.92:7002> keys *
 1) "name"

故障模拟测试(验证高可用)

7.1 模拟主节点宕机(在192.168.7.91上执行)

 # 杀掉7001进程(模拟故障)
 ps -ef | grep 7001 | grep -v grep | awk '{print $2}' | xargs kill -9

7.2 查看集群状态(在192.168.7.92上执行)

 # 登录客户端
 redis-cli -c -h 192.168.7.92 -p 7002
 ​
 192.168.7.92:7002> cluster nodes
 9e2cce99d2562cce50c277cf530167bb42aa7d1d 192.168.7.92:7005@17005 master - 0 1784190405031 7 connected 0-5460
 9a17a37ebc6a79f039df8295311de787dafa8c2d 192.168.7.91:7001@17001 master,fail - 1784190363454 1784190361380 1 disconnected
 7727a1a0f30a1b1b7d3e8dca6a47ce32af655b7f 192.168.7.91:7004@17004 slave 459dd93ade998bfa4853095d7965cda4ced9ebe2 0 1784190406067 3 connected
 d377df61b7ec3b8527e4db08d1b482571793471c 192.168.7.92:7002@17002 myself,master - 0 1784190403000 2 connected 5461-10922
 109dead98182d788bd5bc6fdb8336108a121afa7 192.168.7.93:7006@17006 slave d377df61b7ec3b8527e4db08d1b482571793471c 0 1784190406591 2 connected
 459dd93ade998bfa4853095d7965cda4ced9ebe2 192.168.7.93:7003@17003 master - 0 1784190404504 3 connected 10923-16383

重启7001(它会自动变成7004的从节点)

 # 在192.168.7.91上执行
 redis-server ./redis-cluster/7001/redis.conf
 ​
 # 再次查看集群状态
 redis-cli -c -h 192.168.7.92 -p 7002
 192.168.7.92:7002> cluster nodes
 ​
 # 7001变成了7005的slave

集群管理常用命令

8.1 检查集群健康状态

 redis-cli --cluster check 192.168.7.91:7001

8.2 查看集群中所有节点

 redis-cli -c -h 192.168.7.91 -p 7001 cluster nodes

8.3 查看槽位分配情况

 redis-cli -c -h 192.168.7.91 -p 7001 cluster slots

8.4 添加新节点(如果需要扩容)

 # 假设新增一台机器192.168.7.94:7007
 # 先启动该Redis实例,然后执行:
 redis-cli --cluster add-node 192.168.7.94:7007 192.168.7.91:7001
 ​
 # 添加为从节点(需指定主节点ID)
 redis-cli --cluster add-node 192.168.7.94:7007 192.168.7.91:7001 --cluster-slave --cluster-master-id <主节点ID>

8.5 删除节点

 # 先迁移该节点的槽位(如果是主节点)
 redis-cli --cluster reshard 192.168.7.91:7001
 ​
 # 然后删除节点
 redis-cli --cluster del-node 192.168.7.94:7007 <节点ID>