Redis持久化
持久化是什么
持久化即将内存中的数据写入硬盘,目标是为了之后重用数据或做数据同步。
Redis支持3钟持久化方式
- 快照(RDB,snapshotting),Redis默认的持久化方式
- 只追加文件(AOF,append-only file)
- RDB和AOF的混合持久化(Redis 4.0新增)
3种持久化方式分别是什么
RDB:通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。可以对快照进行备份,可以复制到其他服务器从而创建具有相同数据的服务器副本(Redis主从结构,提高性能),可以原地保留等服务器重启时使用
会阻塞主线程吗:
save命令会阻塞,bgsave会fork出一个子进程,不会阻塞Redis主线程,默认选项为bgsave
AOF:比RDB实时性更好,Redis6.0版本前默认不开启,可以通过appendonly yes开启。
开启后,每执行一条会更改Redis中数据的命令,
Redis就会将该命令写入AOF缓冲区server.aof_buf中,再写入AOF文件,
最后再根据持久化方式的配置来决定何时将系统内核缓存区的数据同步到硬盘,到此,持久化成功。
RDB和AOF的混合持久化:
AOF持久化如何实现
整体流程:客户端发送写命令、Redis执行写操作命令(在内存中)、Redis记录写操作命令到日志(位于硬盘)
1.AOF日志
是什么:保存了Redis执行过的写操作命令的文本文件(不保存读操作命令,因为没意义)
查看:cat
命令
先执行再保存的好处:①避免检查命令是否正确的开销②不会阻塞当前写操作命令的执行
先执行再保存的风险:①执行完未写入宕机导致丢失②可能阻塞下一个写操作命令的执行
综上,我们可以得出AOF日志写回硬盘的时机很重要,引出第二点——写回策略
2.三种写回策略
写入日志的细化流程:执行写操作命令、命令追加到server.aof_buf
缓冲区、I/O系统调用write()
、将aof_buf
缓冲区数据拷贝到内核缓冲区page cache
、内核发起写操作、写入硬盘
在redis.conf
配置文件中的appendfsync
配置项目中有以下3种参数可选:
Always,每次写操作命令执行完毕,同步将AOF日志数据写回硬盘
Everysec,每次写操作命令执行完毕,先将AOF命令写入AOF文件的内核缓冲区,然后每隔1s将缓冲区里的内容写回到硬盘
No,意味着不由Redis控制写回硬盘的时机,由操作系统决定何时将内核缓冲区内容写回硬盘
由于主进程阻塞和减少数据丢失是对立问题,这三个策略无法同时完美解决这两个问题。
- Always策略可以最大程度保证数据不丢失,由于写回频率太高,不可避免的影响主进程性能。
- No策略性能较好,但是操作系统写回硬盘时机不可预知,如果AOF日志内容没有写回,一旦服务器宕机,就会丢失未知数量的数据
- Everysec策略是折中的方式,避免了过高的性能开销,宕机时丢失的数据量是1s内的
这三种策略是怎么实现的呢?——控制fsync()
函数的调用时机 - Always策略就是每次写入AOF文件数据,立即执行fsync函数
- Everysec策略就是创建一个异步任务来执行fsync函数
- No就是永不执行fsync函数
3.AOF重写机制
用来避免AOF日志文件越来越大,在重写时读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到新的AOF文件
,读完之后用新的AOF文件替换现有的
巧妙之处:
- 尽管某个键值对被多条写命令反复修改,最终也只需要用一条命令去记录键值对的最新状态。
- 为了避免AOF重写失败污染现有的AOF文件,这才需要先重写到
新的AOF文件
4.AOF后台重写
因为AOF重写很耗时间,为了避免阻塞主进程,我们用后台子进程bgrewriteaof
来完成重写。
好处:
- 避免阻塞主进程,子进程进行AOF重写,主进程可以继续处理命令请求
- 子进程带有主进程的数据副本,无需考虑加锁保证数据安全
子进程如何拥有主进程一样的数据副本?
主进程通过fork
系统调用生成bgrewriteaof子进程时,操作系统会把主进程的页表复制一份给子进程,页表中记录着虚拟地址和物理地址的映射关系,而不会复制物理内存,即两者的虚拟空间不同,但对应同一个物理空间,从而共享父进程的物理内存数据,节约物理内存资源,但此时页表对应的页表项会标记该物理内尺寸的权限为只读,当父/子进程向这个内存发起写操作时,CPU会触发写保护中断(由于违反权限),操作系统会在写保护中断处理函数里面进行物理内存的复制,并重新设置其内存映射关系,将父子进程的内存读写权限设置为可读写,最后才对内存进行写操作,这个过程称之为写时复制。
简而言之就是,在发生写操作时,操作系统才复制物理内存。
而重写子进程只会对这个内存进行读操作,所以主进程依然可以正常处理命令。
问题1.如果重写过程中主进程修改了已经存在的key-value,就会发生写时复制,但这里只会复制主进程修改的物理内存数据,没修改的部分还是与子进程共享的。