为什么要搭建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、端口号、密码
slaveof 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 parallel-syncs mymaster 1
sentinel failover-timeout mymaster 18000
启动哨兵:到 redis bin 目录下
./redis-sentinel ./sentinel.conf
Redis cluster集群
传统Redis集群存在的问题
- redis的哨兵集群方式,每个节点都保存全量的同步的数据,可能会存在冗余的数据。
- 其次只能允许有一个主的节点,属于中心化的集群。
- Redis哨兵集群模式,主节点只有一个,每个节点都保存全量同步数据,冗余的数据比较多;而在Redis Cluster模式中集群中采用分片集群模式(数据均摊存放),可以减少冗余数据,缺点就是构建该集群模式成本非常高,
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
port 7005
cluster-enabled yes
cluster-config-file 7000nodes.conf
cluster-node-timeout 15000
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 服务
/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密码
/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
6、这时候集群搭建完成,连接集群测试 需要使用redis-cli -c 命令连接集群中6个节点中任何一个节点都可以,注意和之前的连接参数有点不同redis-cli 命令后面多了一个-c参数,表示采用集群的方式连接,连上以后,然后使用cluster nodes 可以查看集群节点信息,如下
/opt/redis/redisCluster/redis-cli -h 192.168.1.19 -p 7000 -a redis123456 -c
RedisCluster集群模式扩容节点
扩容:当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节点增加到集群中
/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即可
/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
到这里扩容完成
RedisCluster实现快速缩容
Redis槽位缩容(执行下面命令)from后面是要删除的redis节点,to后面是卡槽到的redis节点。cluster-slots移动多少卡槽过去
/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
将添加的主从节点都移除之后,至此结束。
|