为什么要搭建Redis集群?
高可用
单个Redis如果因为某种原因宕机的话,可能会导致Redis服务不可用,可以使用主从复制实现一主多从,主节点负责写的操作,从节点负责读的操作,主节点会定期将数据同步到从节点中,保证数据一致性的问题。
Redis主从复制是指:将一台 Redis 服务器的数据复制到其它的 Redis 服务器,前者所在的 Redis 服务器也被称为 “主节点”(Master / Leader),后者则被称为 “从节点”(Slave / Follower)。数据从主节点复制到从节点,主节点的主要任务是实现写如数据的任务(也有读数据的权限),而从节点则只负责读取数据。在 Redis 的默认配置中,每个启动的 Redis 服务都是主节点。
一个主节点可以有多个从节点,但是对于每个从节点来讲,它都只能属于一个主节点。即主节点和从节点之间的对应关系为 1 对 N ,如下图所示:
该主从同步方式存在 如果从节点非常多的话,会导致对主节点同步多个从节点压力非常大,可以采用树状类型解决该问题。
Redis 的主从复制分为以下两个阶段:sync阶段和 command propagate阶段。
sync(同步)阶段
当从节点启动之后,会发送 sync 指令给主节点,要求全量同步数据,具体的步骤如下图所示:
- Slave 节点向 Master 节点发送 sync 指令,以请求数据同步
- Master 节点在接收到 sync 指令后,会执行一次 BGSAVE 指令,将当前 Master 节点中的数据保存到对应的 RDB 文件中。当 Master 节点完成 RDB 文件的导出后,再将导出的 RBD 文件发送给 Slave 节点。由于在这个过程中 Master 节点依旧有可能发生数据写入操作,在这种情况下 Master 节点会将执行的指令放入到对应的缓冲区
- Slave 节点在接受到 Master 节点导出的 RDB 文件之后,会删除现有节点的所有数据,然后加载这个 RDB 文件的内容到 Slave 节点
- 当 Slave 节点数据加载完成之后,Master 会将缓冲区中暂存的指令发送到 Slave 节点
- Slave 执行收到的指令,完成数据的同步
Command Propagate 阶段
这个阶段也被称为 “命令传播” 阶段,数据同步完成之后,如果后续 Master 节点继续收到了新的写入操作的指令,那么也需要将该命令传播到 Slave 节点以完成数据的同步。这个过程就被称为 “命令传播”
从Redis2.8版本以后,过程采用增量和全量同步
全量复制:一般用于在初次的复制场景(从节点与主节点一次建立连接)
增量复制:网络出现问题,从节点再次连接主节点时,主节点补发缺少的数据,每次数据增量同步
如果主节点存在了问题,整个Redis环境是不可以实现写的操作,需要人工更改配置变为主操作
如何解决该问题:使用哨兵机制可以帮助解决Redis集群主从选举策略。
搭建主从复制集群Redis 主节点正常启动。
Redis 从节点配置文件Redis.conf配置:指定主节点的IP、端口号、密码
# replicaofslaveof 192.168.212.160 6379 masterauth 123456
为防止主节点同步数据压力过大,可以采用树状模式,也就是从节点作为主节点也可以有从节点,如下图所示:
Redis的哨兵机制就是解决以上主从复制存在缺陷(如果 Master 节点崩溃了,在上面的情况下不会将 Slave 节点转换为 Master 节点,因此 Master 节点崩溃之后整个 Redis 集群就不能再执行写入操作),解决问题保证Redis高可用,提高系统的可用性,Redis 提供了 Sentinel(哨兵)来实现 Slave 节点到 Master 节点的转换,“哨兵” 节点本质上也是一个 Redis 节点,但是和 Master 节点和 Slave 节点不同,“哨兵” 节点只是监视 Master 节点和 Slave 节点,并不执行相关的业务操作。
哨兵作用:
- 监控 Redis 节点运行状态
- 通知:当被监控的 Redis 节点出现问题时,Sentinel 可以通过向 API 或者管理员以及其它应用发送通知
- 自动故障转移:当一个主服务器不能正常工作时,Sentinel 会开始一次自动故障迁移,它会在失效的 Redis 集群中寻找一个有效的节点,并将它升级为新的 Master 节点,并见原来失效的 Master 节点降级为 Slave 节点。当客户端试图访问已经失效的 Master 节点时,Redis 集群也会想客户端返回新的 Master 节点的地址,使得 Redis 集群可以使用新的 Master 节点代替失效的 Master 节点
- 哨兵机制每个10s时间只需要配置监听我们的主节点就可以获取当前整个Redis集群的环境列表,采用info 命令形式。
- 哨兵不建议是单机的,最好每个Redis节点都需要配置哨兵监听。
- 哨兵集群原理是如何:多个哨兵都执行同一个主的master节点,订阅到相同都通道,有新的哨兵加入都会向通道中发送自己服务的信息,该通道的订阅者可以发现新哨兵的加入,随后相互建立长连接。
- Master的故障发现 单个哨兵会向主的master节点发送ping的命令,如果master节点没有及时的响应,哨兵会认为该master节点为“主观不可用状态”会发送给其他都哨兵确认该Master节点是否不可用,当前确认的哨兵节点数>=quorum(可配置),会实现重新选举。
由于存在多个 哨兵 节点,因此在 Redis Sentinel 中,对于 Redis 节点的下线也有区分:
- 主观下线(Subjectively Down,即 SDOWN):指单个 Sentinel 节点对集群中的节点作出下线判断
- 客观下线(Objectively Down,即 ODOWN):指多个 Sentinel 节点对集群中的节点作出 “SDOWN” 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,作出 Redis 节点下线的判断
一个 Sentinel 节点可以通过向另一个 Sentinel 节点发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的节点已经下线
选举过程:
- 当一个 Sentinel 节点判断 Master 节点不可用时,首先进行 “SDOWN”(主观下线),此时,这个 Sentinel 通过 SENTINEL is-masterdown-by-addr 指令获取其它哨兵节点对于当前 Master 节点的判断情况,如果当前哨兵节点对于当前 Master 节点的下线判断数量超过了在配置文件中定义的票数,那么该 Master 节点就被判定为 “ODOWN”(主观下线)
- Sentinel 节点列表中也会存在一个 Leader Sentinel,该 Sentinel 会从原主节点的从节点中选出一个新的主节点,具体步骤如下所示:
- 首先,过滤i掉所有的 ODOWN 节点
- 选择 slave-priority 最大的节点,如果存在则选择这个节点为新的主节点,如果没有则继续下面的流程
- 选出复制偏移量最大的节点,如果有则返回;如果没有则继续执行下面的流程
- 选择 run_id (服务运行 id) 最小的节点
- 当选择出新的主节点之后,Leader Sentinel 节点会通过 SLAVEOF NO ONE 命令让选择出来的节点成为主节点,然后通过 SLAVEOF 命令让其他节点成为该节点的从节点
在主从复制的基础上,启动哨兵服务,多台redis的哨兵监听同一台master节点,哨兵会自动形成一个哨兵集群。
配置哨兵的配置文件:
sentinel monitor mymaster 192.168.212.160 6379 3(3表示主节点宕机之后,3台哨兵确认之后,才能重新进行选举) sentinel auth-pass mymaster 123456 #主节点的密码 sentinel down-after-milliseconds mymaster 3000#sentinel心跳检测主3秒内无响应,视为挂掉,开始切换其他从为主 sentinel parallel-syncs mymaster 1 #每次最多可以有1个从同步主。一个从同步结束,另一个从开始同步。 sentinel failover-timeout mymaster 18000 #主从切换超时时间
启动哨兵:到 redis bin 目录下
./redis-sentinel ./sentinel.confRedis cluster集群 传统Redis集群存在的问题
- redis的哨兵集群方式,每个节点都保存全量的同步的数据,可能会存在冗余的数据。
- 其次只能允许有一个主的节点,属于中心化的集群。
- Redis哨兵集群模式,主节点只有一个,每个节点都保存全量同步数据,冗余的数据比较多;而在Redis Cluster模式中集群中采用分片集群模式(数据均摊存放),可以减少冗余数据,缺点就是构建该集群模式成本非常高,
Redis3.0开始官方推出了集群模式 RedisCluster,原理:采用hash槽的概念,预先分配16384个卡槽,并且将该卡槽分配给具体服务的节点;通过key进行crc16(key)%16384 获取余数,余数就是对应的卡槽的位置,一个卡槽可以存放多个不同的key,从而将读或者写转发到该卡槽的服务的节点。 最大的优点:动态扩容、缩容。
只有主的节点才有卡槽,从节点没有卡槽。
卡槽作用:决定key存在具体服务器的位置,从而实现均摊存入数据。类似于我们在数据库中的分表。
集群搭建这里在一台机器上面搭建
1、创建留个文件夹
mkdir rediscluster cd rediscluster/ mkdir redis7000 mkdir redis7001 mkdir redis7002 mkdir redis7003 mkdir redis7004 mkdir redis7005
2、每个文件夹中编写一个配置文件,内容如下:
注意:注释要单独放一行、data目录需要先创建好
#后台启动 daemonize yes ## 允许外部访问 protected-mode no #修改端口号,从7000到7005 port 7005 #开启cluster(开启集群,redis默认支持集群),去掉注释 cluster-enabled yes #自动生成 cluster-config-file 7000nodes.conf #节点通信时间 cluster-node-timeout 15000 #对应的7005根据每个端口号修改 logfile /opt/redis/redisCluster/redis7005/redis.log #修改数据文件存储位置 dir /opt/redis/redisCluster/redis7002/data/
3、一次启动6个接口的redis服务
/usr/redis/bin/redis-server /usr/rediscluster/redis7000/redis.conf /usr/redis/bin/redis-server /usr/rediscluster/redis7001/redis.conf /usr/redis/bin/redis-server /usr/rediscluster/redis7002/redis.conf /usr/redis/bin/redis-server /usr/rediscluster/redis7003/redis.conf /usr/redis/bin/redis-server /usr/rediscluster/redis7004/redis.conf /usr/redis/bin/redis-server /usr/rediscluster/redis7005/redis.conf
4、连接一个redis 服务
#使用本地的ip /opt/redis/redisCluster/redis-cli -h 192.168.1.19 -p 7000 -a redis123456
查看redis服务的启动情况:ps -ef | grep redis
5、执行创建cluster 集群命令
注意:redis设置了密码,后面增加-a redis123456输入redis密码
#(建议最好使用服务器的ip地址搭建)上面命令自动建立主从关系(自动建立卡槽),最后数字 1 的意思是:每个主节点有1个从节点 /opt/redis/redisCluster/redis-cli --cluster create 192.168.1.19:7000 192.168.1.19:7001 192.168.1.19:7002 192.168.1.19:7003 192.168.1.19:7004 192.168.1.19:7005 --cluster-replicas 1 -a redis123456 # 执行之后,有个确定操作,输入 yes 继续执行
6、这时候集群搭建完成,连接集群测试
需要使用redis-cli -c命令连接集群中6个节点中任何一个节点都可以,注意和之前的连接参数有点不同redis-cli命令后面多了一个-c参数,表示采用集群的方式连接,连上以后,然后使用cluster nodes可以查看集群节点信息,如下
/opt/redis/redisCluster/redis-cli -h 192.168.1.19 -p 7000 -a redis123456 -cRedisCluster集群模式扩容节点
扩容:当redis数据量日渐增长,当内存不够用的时候,这时候就需要集群扩容了,cluster集群扩容可以增加内存也可以增加节点,因为redis数据都是存在内存中。
原理:原来的节点算好要拿出多少的槽位给新加的节点,新加的节点准备导入的槽位,准备的前提条件就是加入集群,一切准备就绪后,主节点将划分出来的槽位分配给新节点,然后将相关槽位的数据迁移到新的节点
操作步骤:
1、在前面的基础上新建两个文件夹
/opt/redis/redisCluster/redis-server /opt/redis/redisCluster/redis7006/redis.conf /opt/redis/redisCluster/redis-server /opt/redis/redisCluster/redis7007/redis.conf
启动这两个端口的redis服务
2、把7006节点增加到集群中
#最后面7000节点不是一定的,可以写7000-7005任意一节点皆可 /opt/redis/redisCluster/redis-cli --cluster add-node 192.168.1.19:7006 192.168.1.19:7000 -a redis123456
3、新增一个从节点 为7007(后面跟上7006主节点的节点id)
先查看7006在集群中的ID
# 连接集群 /opt/redis/redisCluster/redis-cli -h 192.168.1.19 -p 7000 -c -a redis123456 cluster nodes
找到7006的集群ID,那么执行add-node即可
#172.16.166.122:7000 不是一定的,可以填7000-7005任意一端口,执行增加从节点的命令 /opt/redis/redisCluster/redis-cli --cluster add-node 192.168.1.19:7007 192.168.1.19:7000 --cluster-slave --cluster-master-id e78d7d3f972b425538ee4f1abadc20da12bfb814 -a redis123456
到这里扩容2个节点7006和7007已经完成一半,但还没有分配哈希槽,无法进行写操作,下面开始分配卡槽到
4、分配卡槽
总哈希槽是16384,平均分给3组,每组是5461,现在加多一组到集群,变成4组,平均每组 16384/4=4096,那么每组要抽取多少哈希槽给7006呢?4096/3=1365
执行reshard进行从3组中抽取1365哈希缓存分配给7006
/opt/redis/redisCluster/redis-cli --cluster reshard 192.168.1.19:7000 -a redis123456
执行后会弹出“您要移动多少个插槽(从 1 到 16384)” 输入上面算出来的结果4096
输入4096后会弹出接收者ID,我们输入上面找到的7006的集群ID
然后会弹出分配方式,是平均分配还是从其中一台抽取,我们使用平均分配 all
后面输入 yes即可
到这里扩容分哈希槽就完成了,接下来看分配的结果:
/opt/redis/redisCluster/redis-cli -h 192.168.1.19 -p 7000 -c -a redis123456 cluster nodes
到这里扩容完成
Redis槽位缩容(执行下面命令)from后面是要删除的redis节点,to后面是卡槽到的redis节点。cluster-slots移动多少卡槽过去
# 删除 7006 节点的卡槽,移动到 7000 节点上 /opt/redis/redisCluster/redis-cli -a redis123456 --cluster reshard 192.168.1.19:7000 --cluster-from e78d7d3f972b425538ee4f1abadc20da12bfb814 --cluster-to 9550217baa8a823bb7547ed0f15ea630e22f440a --cluster-slots 1365
移除集群中的节点
/opt/redis/redisCluster/redis-cli -a redis123456 --cluster del-node 192.168.1.19:7000 938ed8f46c9eac385a92e9f80c4ebddc8fdedaaa
将添加的主从节点都移除之后,至此结束。



