Redis持久化,AOF、RDB,混合持久化
Redis 是跑在内存里面的,当程序重启或者服务器崩溃的时候,数据就会丢失,如果业务场景希望重启之后数据还在,就需要做持久化,把数据保存到可永久保存的存储设备中。
Redis 提供了两种方式来实现持久化。
第一个是记录 Redis 执行的命令 AOF,第二种是记录某一个时刻的快照数据 RDB。 这两种各有优缺点,使用的时候可以结合起来。
RDB
1RDB(Redis Database BackUp),记录 Redis 某一个时刻的全部数据,这个方式的本质是快照,直接保存二进制数据到磁盘中去,后序通过加载 RDB 文件恢复数据。
RDB 底层的原理:
当 Redis 停止服务的时候执行的是 save 命令,阻塞执行保存所有的数据。正常情况下面执行的是 bgsave,是异步的操作。
bgsave 命令的原理 :
调用 bgsave 的时候,Redis 使用 unix 的 fork 命令系统调用创建一个子进程,子进程会复制主进程的内存空间,公用父进程的页表结构,使用的是 copy-on-write 机制,就是父子进程最初都是共享一块内存区域。只有数据在被修改的时候才会真正的复制,减少了内存的拷贝成本。
子进程将当前 内存中的数据写入到磁盘上面,父进程继续处理客户端的请求,父进程修改数据的时候需要复制被修改页的内存,不会影响子进程正在生成的快照。
子进程写入完毕后退出,生成 RDB 是 Redis 数据当时的完整快照。
fork 底层使用 copy on write 技术。主进程写的写操作的时候 要先拷贝一份数据,执行写操作。
存在的问题
使用 bgsave 执行快照的时候,如果主线程修改了数据,不管是否共享内存的数据,RBD 快照都无法写入主进程刚刚修改的数据,因为新拷贝了一份内存数据出来。 子进程写入到 RDB 文件中的数据只能是原本的内存数据。
在 RDB 执行持久化期间,刚 fork 时,主进程和子进程共享同一个物理内存,但是途中主进程处理写操作修改了共享内存,于是当前被修改的数据的物理内存先会被复制一份,在极端的情况下面,所有的内存都被修改,此时内存占用时原来的两倍。 内存会被占满。所以在写操作多的情况下面,要留意内存的变化,防止内存满了。 还有在主进程写完之后,崩溃掉了,Redis 将丢失线程在快照期间修改的数据。存在数据安全的漏洞,可能存在短分钟内的数据没有写入到数据文件中去。
AOF
2.AOF(append only File) 记录执行的每条写操作的命令, 不会记录读操作,重启之后通过重新执行命令来恢复数据,AOF 本质是记录**操作日志**,后序通过日志来恢复数据。
redis 默认是没有开启持久化功能的,需要手动修改 redis.conf 文件来配置参数
存储的内容
*3 表示命令由三个单词组成。 $3 表示命令的长度 set 表示命令
Redis 先执行 命令 然后将命令回写到磁盘中去,写道磁盘也是在主线程中执行的,如果操作不当不能让线程阻塞。
Redis 写入 AOF 日志的过程,首先命令追加到缓冲区,然后写入到内核中去,最后由内核将命令写入到磁盘中去,内核写入的时机由三种新三种形式。
有三种写的策略:
- always 同步写回去。 2. everysec 每秒写回
- no 由操作系统控制写回
写入的时机是又内核决定的,不同的写入时机对性能和数据的丢失都是不一样的。
AOF 的重写机制
当执行的命令越来越多的时候,AOF 文件会越来越大,Redis 会重写 AOF 文件。重写 AOF 文件是读取当前数据库中的所有键值对,然后每一个键值对用一条命令记录到新的 AOF 文件中,等全部记录完成之后,将新的 AOF 文件替换现有的 AOF 文件。
重写操作 比如 set name lisi 和 set name wangwu 只会保留第二条命令,第一条命令会删除掉。
重写的过程是非常耗时的,不可能放在主线程中去运行,由后台子进程 bgrewiteaof 来完成。 创建子进程可以·共享父进程的内存数据。以只读的方式
混合化持久
混合使用 AOF 日志和内存快照。
AOF 重写的时候,fork 出现的重写子进程会先与主进程共享的内存数据以 RDB 方式写入 aof 文件中,然后主线程处理的命令被记录在缓冲区内,缓存区内的增量命令以 AOF 形式写入 aof 文件,写完后通知主线程将含以后 aof 格式和 rdb 格式的 aof 文件替换旧的 aof 文件。
牛牛的面试专栏,希望自己在25年可以拿到一份大厂的SP Offer 你的点赞和收藏都是我持续更新的动力