🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# redis-集群 [TOC] ## 一、 redis集群知识介绍 ###1. 集群介绍 Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation)。 Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据,并且在高负载的情况下,这些命令将降低 Redis 集群的性能,并导致不可预测的行为。 Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。 redis集群具备将数据自动切分(split)到多个节点的能力。 ### 2. 集群数据共享 Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。 如果有三个节点,可以简单的如下假设: * 节点 A 负责处理 0 号至 5500 号哈希槽。 * 节点 B 负责处理 5501 号至 11000 号哈希槽。 * 节点 C 负责处理 11001 号至 16384 号哈希槽。 ### 3. 运行机制 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.节点的fail是通过集群中超过半数的master节点检测失效时才生效. 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可 把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key ### 4. 集群的复制 为了使得集群在一部分节点下线或者无法与集群的大多数(majority)节点进行通讯的情况下 仍然可以正常运作, Redis 集群对节点使用了主从复制功能: 集群中的每个节点都有 1 个至 N 个复制品(replica), 其中一个复制品为主节点(master), 而其余的 N-1 个复制品为从节点(slave)。 在之前列举的节点 A 、B 、C 的例子中, 如果节点 B 下线了, 那么集群将无法正常运行, 因为集群找不到节点来处理 5501 号至 11000 号的哈希槽。 假如在创建集群的时候(或者至少在节点 B 下线之前), 我们为主节点 B 添加了从节点 B1,那么当主节点 B 下线的时候, 集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B,继续处理 5501 号至 11000 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了。 不过如果节点 B 和 B1 都下线的话, Redis 集群还是会停止运作。 集群的复制特性重用了 SLAVEOF 命令的代码,所以集群节点的复制行为和 SLAVEOF 命令的复制行为完全相同。 ### 5. 集群的故障转移 在集群里面,节点会对其他节点进行下线检测。 当一个主节点下线时,集群里面的其他主节点负责对下线主节点进行故障移。集群的节点集成了下线检测和故障转移等类似 Sentinel 的功能。 因为 Sentinel 是一个独立运行的监控程序,而集群的下线检测和故障转移等功能是集成在节点里面的,它们的运行模式非常地不同,所以尽管这两者的功能很相似,但集群的实现没有重用 Sentinel 的代码。 ### 6. 在集群里面执行命令的两种情况 集群中的节点会互相告知对方,自己负责处理哪些槽,并写入自己的槽表,手到请求后,会根据槽表来进行检查 1)命令发送到了正确的节点: 命令要处理的键所在的槽正好是由接收命令的节点负责,那么该节点执行命令,就像单机 Redis 服务器一样。 2)命令发送到了错误的节点: 接收到命令的节点并非处理键所在槽的节点,那么节点将向客户端返回一个转向(redirection)错误,告知客户端应该到哪个节点去执行这个命令,客户端会根据错误提示的信息,重新向正确的节点发送命令。 ## 二、 redis集群搭建 ### 1. 规划、搭建过程: 6个redis实例,一般会放到3台硬件服务器, 端口号:7000-7005 注:在企业规划中,一个分片的两个节点,分到不同的物理机,防止硬件主机宕机造成的整个分片数据丢失。 1)安装集群插件 ```sh # EPEL源安装ruby支持 yum install ruby rubygems -y # 使用国内源 gem sources -l gem sources -a http://mirrors.aliyun.com/rubygems/ gem sources --remove http://rubygems.org/ gem install redis -v 3.3.3 gem sources -l ``` 2)集群节点准备 ```sh mkdir /data/redis_m/700{0..5} ``` 7000节点 ```sh cat >/data/redis_m/7000/redis.conf <<'EOF' port 7000 daemonize yes pidfile /data/redis_m/7000/redis.pid loglevel notice logfile "/data/redis_m/7000/redis.log" dbfilename dump.rdb dir /data/redis_m/7000 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOF ``` 7001节点 ```sh cat >/data/redis_m/7001/redis.conf <<'EOF' port 7001 daemonize yes pidfile /data/redis_m/7001/redis.pid loglevel notice logfile "/data/redis_m/7001/redis.log" dbfilename dump.rdb dir /data/redis_m/7001 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOF ``` 7002节点 ```sh cat >/data/redis_m/7002/redis.conf <<'EOF' port 7002 daemonize yes pidfile /data/redis_m/7002/redis.pid loglevel notice logfile "/data/redis_m/7002/redis.log" dbfilename dump.rdb dir /data/redis_m/7002 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOF ``` 7003节点 ```sh cat >/data/redis_m/7003/redis.conf <<'EOF' port 7003 daemonize yes pidfile /data/redis_m/7003/redis.pid loglevel notice logfile "/data/redis_m/7003/redis.log" dbfilename dump.rdb dir /data/redis_m/7003 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOF ``` 7004节点 ```sh cat >/data/redis_m/7004/redis.conf <<'EOF' port 7004 daemonize yes pidfile /data/redis_m/7004/redis.pid loglevel notice logfile "/data/redis_m/7004/redis.log" dbfilename dump.rdb dir /data/redis_m/7004 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOF ``` 7005节点 ```sh cat >/data/redis_m/7005/redis.conf <<'EOF' port 7005 daemonize yes pidfile /data/redis_m/7005/redis.pid loglevel notice logfile "/data/redis_m/7005/redis.log" dbfilename dump.rdb dir /data/redis_m/7005 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOF ``` ### 2. 启动节点: ```sh redis-server /data/redis_m/7000/redis.conf redis-server /data/redis_m/7001/redis.conf redis-server /data/redis_m/7002/redis.conf redis-server /data/redis_m/7003/redis.conf redis-server /data/redis_m/7004/redis.conf redis-server /data/redis_m/7005/redis.conf ``` 查看结果 ```sh [root@db01 ~]# ps -ef |grep redis root 8854 1 0 03:56 ? 00:00:00 redis-server *:7000 [cluster] root 8858 1 0 03:56 ? 00:00:00 redis-server *:7001 [cluster] root 8860 1 0 03:56 ? 00:00:00 redis-server *:7002 [cluster] root 8864 1 0 03:56 ? 00:00:00 redis-server *:7003 [cluster] root 8866 1 0 03:56 ? 00:00:00 redis-server *:7004 [cluster] root 8874 1 0 03:56 ? 00:00:00 redis-server *:7005 [cluster] ``` ### 3. 将节点加入集群管理 ```sh redis-trib.rb create --replicas 1 127.0.0.1:7000 \ 127.0.0.1:7001 \ 127.0.0.1:7002 \ 127.0.0.1:7003 \ 127.0.0.1:7004 \ 127.0.0.1:7005 ``` ### 4. 集群状态查看 1)集群主节点状态 ```sh redis-cli -p 7000 cluster nodes | grep master ``` 2)集群从节点状态 ```sh redis-cli -p 7000 cluster nodes | grep slave ``` ### 5. 集群节点管理 1)增加新的节点 创建目录 ```sh mkdir /data/redis_m/7006 mkdir /data/redis_m/7007 ``` 增加7006节点配置 ```sh cat >/data/redis_m/7006/redis.conf <<'EOF' port 7006 daemonize yes pidfile /data/redis_m/7006/redis.pid loglevel notice logfile "/data/redis_m/7006/redis.log" dbfilename dump.rdb dir /data/redis_m/7006 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOF ``` 增加7006节点配置 ```sh cat >/data/redis_m/7007/redis.conf <<'EOF' port 7007 daemonize yes pidfile /data/redis_m/7007/redis.pid loglevel notice logfile "/data/redis_m/7007/redis.log" dbfilename dump.rdb dir /data/redis_m/7007 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOF ``` 启动新节点 ```sh redis-server /data/redis_m/7006/redis.conf redis-server /data/redis_m/7007/redis.conf ``` 2)添加主节点: ```sh redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000 ``` 3)转移slot(重新分片) ```sh redis-trib.rb reshard 127.0.0.1:7000 ``` 4)添加从节点 ```sh redis-trib.rb add-node --slave --master-id bff7d6e603578033f53865de3e55fb2b8c526b60 127.0.0.1:7007 127.0.0.1:7000 ``` ### 6. 删除节点 1)将需要删除节点slot移动走 ```sh redis-trib.rb reshard 127.0.0.1:7000 ``` 2)删除一个节点 删除master节点之前首先要使用reshard移除master的全部slot,然后再删除当前节点 ```sh # 主节点删除: redis-trib.rb del-node 127.0.0.1:7006 bff7d6e603578033f53865de3e55fb2b8c526b60 # 从节点删除: redis-trib.rb del-node 127.0.0.1:7007 2af3da4252ad1a7334d476e1b56498b85a1b488c ```