单点Redis的问题
数据丢失问题
Redis是内存存储,服务重启可能会丢失数据
并发能力问题
单节点Redis并发能力虽然不错,但也无法满足如618这样的高并发场景
故障恢复问题
如果Redis宕机,则服务不可用,需要一种自动的故障恢复手段
存储能力问题
Redis基于内存,单节点能存储的数据量难以满足海量数据需求
一、Redis持久化
1、RDB持久化
RDB
RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。
快照文件称为RDB文件,默认是保存在当前运行目录。
Redis停机时会执行一次RDB。
Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:
RDB的其它配置也可以在redis.conf文件中设置:
bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件。
fork采用的是copy-on-write技术:
总结:
RDB方式bgsave的基本流程?
RDB会在什么时候执行?save 60 1000代表什么含义?
RDB的缺点?
2、AOF持久化
AOF
AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。
AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF:
AOF的命令记录的频率也可以通过redis.conf文件来配:
配置项 | 刷盘时机 | 优点 | 缺点 |
Always | 同步刷盘 | 可靠性高,几乎不丢数据 | 性能影响大 |
everysec | 每秒刷盘 | 性能适中 | 最多丢失1秒数据 |
no | 操作系统控制 | 性能最好 | 可靠性较差,可能丢失大量数据 |
因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。
Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置:
RDB和AOF各有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。
RDB | AOF | |
持久化方式 | 定时对整个内存做快照 | 记录每一次执行的命令 |
数据完整性 | 不完整,两次备份之间会丢失 | 相对完整,取决于刷盘策略 |
文件大小 | 会有压缩,文件体积小 | 记录命令,文件体积很大 |
宕机恢复速度 | 很快 | 慢 |
数据恢复优先级 | 低,因为数据完整性不如AOF | 高,因为数据完整性更高 |
系统资源占用 | 高,大量CPU和内存消耗 | 低,主要是磁盘IO资源 但AOF重写时会占用大量CPU和内存资源 |
使用场景 | 可以容忍数分钟的数据丢失,追求更快的启动速度 | 对数据安全性要求较高常见 |
二、Redis主从
1、搭建主从架构
单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。
总结:
假设有A、B两个Redis实例,如何让B作为A的slave节点?
2、主从数据同步原理
主从第一次同步是全量同步:
master如何判断slave是不是第一次来同步数据?这里会用到两个很重要的概念:
因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以判断到底需要同步哪些数据
总结:
简述全量同步的流程?
三、Redis哨兵
1、哨兵的作用和原理
哨兵的作用
Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:
服务状态监控
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
选举新的master
一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:
如何实现故障转移
当选中了其中一个slave为新的master后(例如slave1),故障的转移的步骤如下:
总结:
Sentinel的三个作用是什么?
Sentinel如何判断一个redis实例是否健康?
故障转移步骤有哪些?
2、搭建哨兵集群
3、RedisTemplate的哨兵模式
在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。
首先,我们引入的Demo工程:
1.在pom文件中引入redis的starter依赖:
2.然后在配置文件application.yml中指定sentinel相关信息:
3.配置主从读写分离
这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择:
四、Redis分片集群
1、搭建分片集群
分片集群结构
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
使用分片集群可以解决上述问题,分片集群特征:
2、散列插槽
Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到:
数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:
例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。
总结:
Redis如何判断某个key应该在哪个实例?
如何将同一类数据固定的保存在同一个Redis实例?
3、集群伸缩
添加一个节点到集群
redis-cli --cluster提供了很多操作集群的命令,可以通过下面方式查看:
比如,添加节点的命令:
4、故障转移
当集群中有一个master宕机会发生什么呢?
1.首先是该实例与其它实例失去连接
2.然后是疑似宕机:
3.最后是确定下线,自动提升一个slave为新的master:
数据迁移
利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。其流程如下:
手动的Failover支持三种不同模式:
5、RedisTemplate访问分片集群
RedisTemplate底层同样基于lettuce实现了分片集群的支持,而使用的步骤与哨兵模式基本一致:
与哨兵模式相比,其中只有分片集群的配置方式略有差异,如下: