目录
请你谈谈Redis持久化
Redis持久化是什么?
持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。
Redis 的持久化主要有两大机制,即 AOF(Append Only File)日志和 RDB 快照。
谈谈AOF日志是怎么实现的?
和数据库写前日志不同,redis采用写后日志。并且类似于mysql里面binlog的statement格式,记录的是命令操作。
为啥要写后日志呢?
-
好处:
为了避免检查开销,避免出现记录错误命令的情况。
为了不阻塞当前的写操作。 -
风险:
如果刚执行完一个命令,还没有来得及记日志就宕机了,那么这个命令和相应的数据就有丢失的风险。
AOF 日志是在主线程中执行写回的,可能会给下一个操作带来阻塞风险。
怎么解除丢失和阻塞风险呢?
控制一个写命令执行完后 AOF 日志写回磁盘的时机。
三种写回策略
- Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
- Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
- No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
AOF日志的优缺点是什么?
- 优点:
1、数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次。
2、通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。
3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall)) - 缺点:
1、AOF 文件比 RDB 文件大,且恢复速度慢。
2、数据集大的时候,比 rdb 启动效率低。
日志文件太大了怎么办?谈谈AOF重写机制
AOF重写机制:对过大的AOF文件进行重写,以此来压缩AOF文件的大小。
实现:检查当前键值数据库中的键值对,记录键值对的最终状态,从而实现对某个键值对 重复操作后产生的多条操作记录压缩成一条的效果。进而实现压缩AOF文件的大小。
AOF 重写仍然很耗时啊,会阻塞吗?咋重写的?
和 AOF 日志由主线程写回不同,重写过程是由后台子进程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
重写过程:
一个拷贝:每次执行重写时,主线程 fork 出后台的 bgrewriteaof 子进程。此时,fork 会把主线程的内存拷贝一份给 bgrewriteaof 子进程,这里面就包含了数据库的最新数据。然后,bgrewriteaof 子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。
两处日志:
- 第一处日志就是指正在使用的 AOF 日志,Redis 新来的写操作写到它的缓冲区。这样一来,即使宕机了,旧 AOF 日志的操作仍然是齐全的,可以用于恢复。
- 第二处日志就是指新的 AOF 重写日志。这个操作也会被写到重写日志的缓冲区。这样,重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,我们就可以用新的 AOF 文件替代旧文件了。
------------------------------------------------------AOF日志恢复数据有点小慢,RDB登场
RDB咋实现的?
和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。
Redis 的数据都在内存中,为了提供所有数据的可靠性保证,它执行的是全量快照,也就是说,把内存中的所有数据都记录到磁盘中
通过 bgsave 命令来执行全量快照,这既提供了数据的可靠性保证,也避免了对 Redis 的性能影响。save会阻塞。
RDB优缺点是什么?
- 优点
1、产生只有一个数据文件 dump.rdb,方便持久化。
2、容灾性好,一个文件可以保存到安全的磁盘。
3、性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能
4.相对于数据集大时,比 AOF 的启动效率更高。 - 缺点:
1、数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)
快照时数据能修改吗?
可以,Redis 就会借助操作系统提供的写时复制技术,在执行快照的同时,正常处理写操作。
如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本(键值对 C’)。然后,主线程在这个数据副本上进行修改。同时,bgsave 子进程可以继续把原来的数据(键值对 C)写入 RDB 文件。
既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
可以每秒做一次快照吗?
不行。如果频繁地执行全量快照,也会带来两方面的开销:
- 一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。
- 另一方面,bgsave 子进程需要通过 fork 操作从主线程创建出来。子进程在创建后不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。如果频繁 fork 出 bgsave 子进程,这就会频繁阻塞主线程了(所以,在 Redis 中如果有一个 bgsave 在运行,就不会再启动第二个 bgsave 子进程)。
解决:可以做增量快照,在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。
- 混合使用 AOF 日志和内存快照。
内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的简单优势
AOF和RDB比较
- AOF文件比RDB更新频率高,优先使用AOF还原数据。
- AOF比RDB更安全也更大
- RDB性能比AOF好
- 如果两个都配了优先加载AOF
如何选择合适的持久化方式?
-
如果想达到高的数据安全性,你应该同时使用两种持久化功能。在这种情况下,当 Redis 重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
-
如果你非常关心你的性能, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。
-
有很多用户都只使用AOF持久化everysec,但并不推荐这种方式,因为定时生成RDB快照非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快。
-
如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
Redis持久化数据和缓存怎么做扩容?
如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。
一致性哈希
一致性哈希详细图解
如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。