Redis之持久化机制和实现原理

1.Redis 持久化的意义

redis的数据全部在内存中,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证redis的数据在发生突发状况时不会丢失、或者只丢失少量,于是必须根据一些策略来把redis内存中的数据写到磁盘中,这样当redis服务重启时,就会将硬盘中的数据恢复到内存中。Redis持久化的意义就是为了保证突然宕机,内存数据不会全部丢失。

2.Redis 持久化机制

redis有两种持久化机制:RDB和AOF。每种持久化机制各有优缺点,了解每种持久化机制的原理对我们使用Redis有很大的帮助。Redis4.0后支持RDB和AOF两种持久化机制混合使用,所以存在三种持久化策略。

(1)RDB持久化

RDB是基于快照一次的全量备份,即周期性的把redis当前内存中的全量数据写入到一个快照文件中(周期时间可以通过配置来调整)。redis是单线程程序,这个线程要同时负责多个客户端的读写请求,还要负责周期性的把当前内存中的数据写到快照文件中RDB中,数据写到RDB文件是IO操作,IO操作会严重影响redis的性能,甚至在持久化的过程中,读写请求会阻塞,为了解决这些问题,Redis采用多进程来同时进行读写请求和持久化操作。这样又会导致另外的问题,持久化的过程中,内存中的数据还在改变,假如redis正在进行持久化一个大的数据结构,在这个过程中客户端发送一个删除请求,把这个大的数据结构删掉了,这时候持久化的动作还没有完成,那么redis该怎么办呢?

redis使用操作系统的多进程COW(Copy On Write)机制来实现快照的持久化,在持久化过程中调用 glibc(Linux下的C函数库) 的函数fork()产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端的读写请求。子进程刚刚产生时,和父进程共享内存里面的代码段和数据段,这是Linux操作系统的机制,为了节约内存资源,所以尽可能让父子进程共享内存,这样在进程分离的一瞬间,内存的增长几乎没有明显变化。

#1、linux中若父进程退出,子进程尚未结束,子进程不会立即退出。
	在linux中,所有进程都有一个共同的父进程systemd,如果父进程退出了,子进程还没运行结束,子进程会被systemd(老版本的linux是initd)收养。

#2、RDB持久化时,Redis会fork()一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端的读写请求。

子进程对当前内存中的数据进行持久化时,并不会修改当前的数据结构,如果父进程收到了读写请求,那么会把处理的那一部分数据复制一份到内存,对复制后的数据进行修改。所以即使对某个数据进行了修改,redis持久化到RDB中的数据也是未修改的数据,这也是把RDB文件称为"快照"文件的原因,子进程所看到的数据在它被创建的一瞬间就固定下来了,父进程修改的某个数据只是该数据的复制品。

实际上,内存中的全量数据由一个个的"数据段页面"组成,每个数据段页面的大小为4K,客户端要修改的数据在哪个页面中,就会复制一份这个页面到内存中,这个复制的过程称为"页面分离",在持久化过程中,随着分离出的页面越来越多,内存就会持续增长,但是不会超过原内存的2倍,因为在一次持久化的过程中,几乎不会出现所有的页面都会分离的情况,读写请求针对的只是原数据中的小部分,大部分redis数据还是"冷数据"。RDB过程整个过程如下图:

热点数据和冷数据是什么

  • 热点数据:读取频率高,如果不做缓存,给数据库造成很大的压力,可能被击穿。
  • 冷数据:读取频率低,数据设置缓存后有可能没有被访问就被挤出内存(超时dele)。

RDB有两种触发方式:自动触发和手动触发。

  • (1)自动触发:在 redis.conf 配置文件中的 SNAPSHOTTING 下配置save参数,来触发Redis的 RDB 持久化条件,也就是什么时候将内存中的数据保存到硬盘。比如“save m n”:表示m秒内数据集存在n次修改时,自动触发bgsave。
//默认如下配置:
save 900 1:每隔900s(15min),如果有超过1个key发生了变化,就写一份新的RDB文件
save 300 10:每隔300s(5min),如果有超过10个key发生了变化,就写一份新的RDB文件
save 60 10000:每隔60s(1min),如果有超过10000个key发生了变化,就写一份新的RDB文件
(配置多种策略可以同时生效,无论满足哪一种条件都会写一份新的RDB文件)
  • (2)手动触发:手动生成新的RDB文件,执行Redis的save、bgsave命令。
save:阻塞主进程,直到生成新的RDB文件;执行save命令期间,Redis不能处理其他命令。
bgsave:异步生成RDB文件,fork子进程去生成新的RDB文件,主进程不阻塞。

(2)AOF持久化

AOF(Append-only file)日志存储的是redis服务器的顺序指令序列,即对内存中数据进行修改的指令记录。当redis收到客户端修改指令后,先进行参数校验,如果校验通过,先把该指令存储到AOF日志文件中,也就是先存到磁盘,然后再执行该修改指令。

redis把操作指令追加到AOF文件这个过程,并不是直接写到AOF文件中,而是先写到操作系统的内存缓存中,这个内存缓存是由操作系统内核分配的,然后操作系统内核会异步地把内存缓存中的redis操作指令刷写到AOF文件中。当redis宕机后重启后,可以读取该AOF文件中的指令,进行数据恢复,恢复的过程就是把记录的指令再顺序执行一次,这样就可以恢复到宕机之前的状态。

这儿存在一个问题,假如内存缓存中的redis指令还没有来得及刷写到AOF文件中就宕机了,那么这部分未刷写的指令就会丢失,不过,glibc函数库提供了 fsync() 函数,该函数可以将指定文件的内容强制从内存缓存中刷写到磁盘上。fsync操作的周期对redis的性能有很大影响,如何配置将在本文后续的内容中给出建议。AOF过程如下图:

redis在长期运行过程中,AOF日志会越来越大,如果redis服务重启后根据很大的AOF文件来顺序执行指令,将会非常耗时,导致redis服务长时间无法对外提供服务,所以需要对AOF文件进行"瘦身""瘦身"的过程称作AOF重写(rewrite)。

AOF Rewrite 的原理是,主进程fork一个子进程,对当前内存中的数据进行遍历,转换成一系列的redis操作指令,并序列化到一个新的AOF日志中,然后把序列化操作期间新收到的操作指令追加到新的AOF文件中,追加完毕后就立即替换旧的AOF文件,这样就完成了"瘦身"工作,即AOF Rewrite。AOF Rewrite过程如下图:

#1、AOF持久策略:fsync的策略,默认为everysec
appendfsync everysec
# everysec:每秒fsync一次,如果Redis宕机,1秒内的指令丢失。
# no:redis不主动fsync,完全交由操作系统决定
# always:1条指令fsync一次,保证数据一条不丢失

 

(3)混合持久化

redis-4.x后支持了RDB和AOF混合使用。重启redis时,我们很少使用RDB来恢复内存状态,因为会丢失大量数据。我们通常使用AOF日志重放,但是重放AOF日志性能相对RDB来说要慢很多,这样在redis实例很大的情况下,启动需要花费很长的时间。redis-4.0为了解决这个问题,带来了一个新的持久化选项——混合持久化。将RDB文件的内容和增量的AOF日志文件存在一起,这里的AOF日志不再是全量 的日志,而是RDB久化开始 到 RDB持久化结束的这段时间发生的增量AOF日志,通常这部分AOF日志很小。redis-4.x混合持久化机制如下图:

3.redis 持久化机制对比

(1)RDB的优缺点

优点:

  • RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去。

  • 生成RDB文件的时候,主进程不需要进行任何磁盘IO操作。当进行RDB持久化时,对redis服务处理读写请求的影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可。生成一次RDB文件的过程就是把当前时刻内存中的数据一次性写入文件中,而AOF则需要先把当前内存中的小量数据转换为操作指令,然后把指令写到内存缓存中,然后再刷写入磁盘。

  • RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。AOF存放的是指令日志,做数据恢复的时候,要回放和执行所有的指令日志,从而恢复内存中的所有数据;而RDB,就是一份数据文件,恢复的时候,直接加载到内存中即可。

缺点:

  • RDB方式数据没办法做到实时持久化/秒级持久化,会导致数据丢失。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据。这个问题,也是RDB最大的缺点,就是不适合做第一优先的恢复方案,如果你依赖RDB做第一优先恢复方案,会导致数据丢失的比较多。

  • RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题(版本不兼容)。

  • RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,甚至数秒。所以一般不要让生成RDB文件的间隔太长,否则每次生成的RDB文件太大了,对redis本身的性能会有影响。

(2)AOF的优缺点

优点:

  • AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据。

  • AOF日志文件以append-only模式(追加)写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。

  • AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite的时候,会对其中的指令进行压缩,会创建出一份需要恢复数据的最小日志出来。

  • AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据。

缺点:

  • 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大。因为AOF是指令文件,RDB是二进制文件。

  • AOF的写性能比RDB的写性能低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的,只不过比起RDB来说性能低,如果要保证一条数据都不丢,也是可以的,AOF的fsync设置成每写入一条数据,fsync一次,但是这样,redis的性能会大大下降。

  • 基于AOF文件做恢复的速度不如基于RDB文件做恢复的速度。

(3)混合持久化的优缺点

  • 优点:结合了RDB和AOF的优点,使得数据恢复的效率大幅提升

  • 缺点:兼容性不好,redis-4.x新增,虽然最终的文件也是.aof格式的文件,但在4.0之前版本都不识别该aof文件,同时由于前部分是RDB格式,阅读性较差。

(4)如何选择redis持久化机制

RDB和AOF到底该如何选择

  • 不要仅仅使用RDB,因为那样会导致丢失很多数据。

  • 也不要仅仅使用AOF,一是数据恢复慢,二是可靠性也不如RDB,毕竟RDB文件中存储的就是某一时刻实实在在的数据,而AOF只是操作指令,把数据转换为操作指令不一定是百分百没问题的。

  • 综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复。

(5)AOF和RDB同时工作

  • redis在写RDB文件的时候不会执行AOF rewrite;redis在执行AOF rewrite的时候不会生成新的RDB。

  • 如果redis正在生成新的RDB文件,此时用户执行bgrewriteaof命令手动重写AOF文件,那么等RDB快照生成之后,才会去执行AOF rewrite。

  • 同时有RDB文件和AOF日志文件,那么redis重启的时候,会优先使用AOF进行数据恢复,因为其中的日志更完整。

4.redis 持久化机制的配置

######################### 通用 #########################

# 持久化文件(包括RDB文件和AOF文件)的存储目录,默认.
dir dir /home/hadoop/data/redis/6379

######################### RDB #########################

# RDB文件的文件名称,默认dump.rdb
dbfilename dump.rdb

# 生成RDB文件的策略,默认为以下3种,意思是:
# 每隔60s(1min),如果有超过10000个key发生了变化,就写一份新的RDB文件
# 每隔300s(5min),如果有超过10个key发生了变化,就写一份新的RDB文件
# 每隔900s(15min),如果有超过1个key发生了变化,就写一份新的RDB文件
# 配置多种策略可以同时生效,无论满足哪一种条件都会写一份新的RDB文件
save 900 1
save 300 10
save 60 10000

# 是否开启RDB文件压缩,该功能可以节约磁盘空间,默认为yes
rdbcompression yes

# 在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏
# 如果在启动时检查发现文件损坏,则停止启动,默认yes
rdbchecksum yes

######################### AOF #########################

# 是否开启AOF机制,默认为no
appendonly yes

# AOF文件的名称,默认为appendonly.aof
appendfilename "appendonly.aof"

# fsync的策略,默认为everysec
# everysec:每秒fsync一次
# no:redis不主动fsync,完全交由操作系统决定
# always:1条指令fsync一次
appendfsync everysec

# AOF文件rewrite策略
# 当上一次重写后的AOF文件的增长比例达到100%
# 比如上一次重写AOF文件后,新文件大小为128M
# 当新文件再次增长了100%,达到了256M
# 并且增长了100%后的文件的大小大于64M,那么开始重写AOF文件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 是否加载破损的AOF文件,默认为yes,如果设置为no
# 那么redis启动时如果发现AOF文件破损,就会报错并且拒绝启动redis服务。
aof-load-truncated yes

######################### 混合持久化 #########################

# 是否开启混合持久化机制,默认为no
aof-use-rdb-preamble no

5.其他相关命令

  • 手动生成新的RDB文件
# 阻塞主进程,直到生成新的RDB文件
save 
# 异步生成RDB文件,fork子进程去生成新的RDB文件,主进程不阻塞
bgsave
  • 手动重写AOF文件
bgrewriteaof
  • 停止redis服务
# 安全停止redis服务,在停止之前会生成一份新的RDB文件
redis-cli SHUTDOWN
# 不安全,会造成数据丢失
kill -9 redis_pid
  • 检查持久化文件
# 检查AOF文件
redis-check-aof /your/path/appendonly.aof
# 检查RDB文件
redis-check-rdb /your/path/dump.rdb
  • 修复AOF文件
#如果redis在append数据到AOF文件时,机器宕机了,可能会导致AOF文件破损,使用以下命令修复AOF文件
$REDIS_HOME/bin/redis-check-aof --fix
  • 查看持久化信息
# 查看持久化信息
info Persistence
# 查看状态信息
info stats

                                                       

                                                                                                                           202年06月06日 晚 于北京记

 

  • 21
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些关于 Redis 持久化的可能面试问题: 1. Redis持久化有哪些方式? Redis持久化两种方式,一种是 RDB 持久化,一种是 AOF 持久化。 2. RDB 持久化和 AOF 持久化有什么区别? RDB 持久化是将 Redis 在内存中的数据快照保存到磁盘上,而 AOF 持久化则是将 Redis 执行的每条写命令记录到磁盘上。RDB 持久化可以节约磁盘空间,但可能会丢失最近的一些数据,而 AOF 持久化可以保证数据不会丢失,但可能会占用更多的磁盘空间和写入时间。 3. Redis持久化机制是如何保证数据一致性的? Redis持久化机制可以通过在每次写操作后立即同步到磁盘,或者设置定期同步时间来保证数据一致性。 4. Redis持久化可以在运行时进行吗? 可以,Redis持久化可以在运行时进行配置和切换,例如可以在运行时从 RDB 切换到 AOF 持久化,或者从 AOF 切换到 RDB 持久化。 5. Redis持久化会对性能产生影响吗? 会,Redis持久化会增加磁盘 I/O 开销,可能会对写入性能产生一定的影响,但可以通过合理的配置来平衡性能和数据一致性。 6. Redis持久化可以与 Redis 集群一起使用吗? 可以,Redis持久化可以与 Redis 集群一起使用,但需要注意配置文件的设置和数据同步的策略。 总之,Redis持久化是保证数据一致性和可靠性的重要手段,需要根据具体的业务需求和性能要求来选择合适的持久化方式,并进行合理的配置和优化。在面试中,还需要了解 Redis 持久化原理机制、优缺点、与集群的结合等方面的知识。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值