深入理解redis持久化—AOF日志

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介: 深入理解redis持久化—AOF日志

redis为什么需要持久化

redis是内存数据库,redis所有的数据都保存在内存中

如果此时pc关机或重启,那么内存中的用户数据岂不是丢失了?redis这么不安全吗?

作为数据库,保证数据的安全,持久是基本需求,redis采用了AOF和RDB两种持久化方式,将用户数据以特殊形式保存在磁盘中,确保重启时可以恢复之前的内存数据状态

AOF(Append Only File)日志

redis的AOF持久化方式是:redis每执行一次写操作,就将对应的命令记录到一个磁盘文件中,redis一旦宕机,重启时重新执行这些命令就可以恢复之前的数据状态

这种保存写操作命令到日志的持久化方式,就是 Redis 里的 AOF(Append Only File) 持久化功能

写日志的步骤:

1.写入aof内核缓冲区

2.将内核缓冲区的数据写入磁盘

Redis 是先执行写操作命令后,才将该命令记录到 AOF 日志里的,这么做其实有两个好处:

1.避免额外的检查,如果一条命令不符合协议的语法,那么这条语句是不会被执行的,如果先写入日志,就会导致恢复数据时,这条命令失效,造成了不必要的性能开销

2.不会阻塞当前写操作的执行,因为执行命令和写日志两个操作都是由主进程进行的,先保证写操作的执行,再进行写日志

AOF持久化的缺陷

1.由于执行写操作和写日志是两个串行的操作,如果在写入日志之前redis故障,就会导致数据丢失

2.写日志操作虽然不会阻塞上一个写操作的执行,但是会阻塞下一个写操作的执行

问题根源——写日志的时机

我们刚刚介绍的,先执行写操作,随后写日志其实是redis日志写策略的一种,现在介绍redis提供的写日志的三种策略

1.Always:每次进行写操作后,将命令写入aof内核缓冲区,随即写入磁盘

2.Everysec:每次进行写操作后,将命令写入aof内核缓冲区,每隔一秒将数据写入磁盘

3.NO:每次进行写操作后将命令写入aof内核缓冲区,由操作系统决定写磁盘的时机

不难发现,每次进行写操作后都必须将命令写入内核aof内核缓冲区,这个过程并不耗时,容易造成阻塞的是写磁盘操作

三种策略的优缺点:

操作系统何时将aof缓冲区的数据写入磁盘?

当应用程序向文件写入数据时,内核通常先将数据复制到内核缓冲区中,然后排入队列,然后由内核决定何时写入硬盘,也就是说,内核缓冲区不止由aof的数据,还有其它的数据,真正的写磁盘时机由操作系统的策略决定

写磁盘时机可以由程序员决定吗?
fsync函数是操作系统提供的同步函数,可以强制让操作系统立即将内核缓冲区的数据写入到磁盘中
上面提到的 Always和Everysec两种写磁盘策略本质上就是调用了fsync函数

AOF重写机制

聪明的你,有没有发现AOF日志会记录一些无效信息?

比如,我执行了set name wjq,随后又执行了set name wjq++,此时数据库中name对应的值实际上是wjq++,而wjq这个值被覆盖了,是无效的,而AOF全部记录了这两条命令,并在恢复数据时重新执行这两条命令,而实际上只需要记录第二条命令,这无疑造成了性能浪费

那么,如何判断某条命令(set name wjq)可以不被记录呢?

很简单,只要查看数据库中现有的数据(wjq++),其中的数据是恢复时所必需的

所以,AOF重写机制就是

读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到「新的 AOF 文件」,等到全部记录完后,就将新的 AOF 文件替换掉现有的 AOF 文件。

重写工作完成后,就会将新的 AOF 文件覆盖现有的 AOF 文件,这就相当于压缩了 AOF 文件,使得 AOF 文件体积变小了。

AOF后台重写

之所以使用AOF重写机制,不是因为AOF记录了无效的信息,而是因为当数据量过大时,AOF文件占用空间过多,我们需要将AOF文件进行压缩

所以,AOF重写机制的触发时机是:当 AOF 文件大于 64M 时

触发 AOF 重写时,比如当 AOF 文件大于 64M 时,就会对 AOF 文件进行重写,这时是需要读取所有缓存的键值对数据,并为每个键值对生成一条命令,然后将其写入到新的 AOF 文件,重写完后,就把现在的 AOF 文件替换掉

你有没有发现,在正常的AOF日志写操作时,是对每一条命令写入aof缓冲区,这个过程并不耗时

但AOF重写时,AOF文件已经超过了64M,这时进行生成命令、写入新文件的操作相当耗时,万万不能放在主进程中进行,那怎么办呢?

所以,Redis 的重写 AOF 过程是由后台子进程 bgrewriteaof 来完成的

当需要进行AOF重写时,fork出一个子进程,由子进程执行重写操作,这样就不会阻塞主进程了

重写期间数据不一致的问题

考虑这样的情况:在子进程进行AOF重写操作时,主进程添加或修改了新的数据,这时子进程只拥有fork时刻的父进程的副本,而没有新添加的数据,并且在AOF重写完成后会用新AOF文件覆盖旧的AOF文件,也就是说,这种数据不一致会导致AOF重写期间添加和修改的数据丢失

解决:

既然在AOF重写期间的新数据只会出现在父进程,而不会出现在子进程,那我们将新数据追加到子进程不就好了

方案:

父进程拥有aof缓冲区

子进程拥有aof重写缓冲区

1.先执行客户端发送的写操作命令

2.将命令写入父进程aof缓冲区

3.将命令写入子进程aof重写缓冲区

这样就解决了父子进程数据不一致和数据丢失的问题

总结

1.AOF日志的持久化具体过程:每执行一条写命令,将该命令写入aof缓冲区,然后由三种写策略(always、everysec、no)决定何时将aof缓冲区数据写入磁盘文件

2.在数据库恢复时,重放磁盘中AOF文件中保存的命令,就实现了内存数据的恢复

3.由于aof记录每一条写命令,会造成记录无效数据的情况,并且数据量大时,aof文件的体积也会过大

为缓解aof的空间占用,redis设计了aof重写的机制,它会扫描数据库中的键值对,并为之生成命令,写入一个新的aof文件中,全部键值对写入完成后,新的aof文件会覆盖旧aof文件,这个过程避免了无效命令的记录,压缩了aof文件体积

大时,aof文件的体积也会过大

为缓解aof的空间占用,redis设计了aof重写的机制,它会扫描数据库中的键值对,并为之生成命令,写入一个新的aof文件中,全部键值对写入完成后,新的aof文件会覆盖旧aof文件,这个过程避免了无效命令的记录,压缩了aof文件体积

不过由于执行aof重写操作的时机是旧aof文件超过64M,也就是说aof重写操作将会很耗时,redis使用一个fork出的子进程来执行这个任务,但是在子进程进行aof重写时,如果父进程产生了新aof数据,会造成数据不一致,且在子进程完成aof重写并覆盖旧aof文件后,这些多出的不一致数据会丢失,所以在aof重写期间追加的新aof数据会先写入父进程aof缓冲区,再写入子进程aof重写缓冲区,解决了数据不一致和数据丢失的问题

推荐学习 https://xxetb.xetslk.com/s/p5Ibb

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1天前
|
存储 缓存 JSON
Redis-持久化-淘汰机制-IO策略
Redis-持久化-淘汰机制-IO策略
|
8天前
|
存储 NoSQL Redis
redis大key对持久化的影响
redis大key对持久化的影响
14 0
|
8天前
|
NoSQL 安全 Redis
redis持久化方式—RDB
redis持久化方式—RDB
22 0
|
27天前
|
存储 缓存 NoSQL
redis 高可用与 持久化
redis 高可用与 持久化
|
30天前
|
存储 NoSQL 程序员
Redis(持久化 -- RDB & AOF)
Redis(持久化 -- RDB & AOF)
33 2
|
1月前
|
NoSQL 算法 Java
【redis源码学习】持久化机制,java程序员面试算法宝典pdf
【redis源码学习】持久化机制,java程序员面试算法宝典pdf
|
1月前
|
存储 监控 负载均衡
保证Redis的高可用性是一个涉及多个层面的任务,主要包括数据持久化、复制与故障转移、集群化部署等方面
【5月更文挑战第15天】保证Redis高可用性涉及数据持久化、复制与故障转移、集群化及优化策略。RDB和AOF是数据持久化方法,哨兵模式确保故障自动恢复。Redis Cluster实现分布式部署,提高负载均衡和容错性。其他措施包括身份认证、多线程、数据压缩和监控报警,以增强安全性和稳定性。通过综合配置与监控,可确保Redis服务的高效、可靠运行。
203 2
|
1月前
|
存储 NoSQL 调度
Redis源码、面试指南(4)单机数据库、持久化、通知与订阅(下)
Redis源码、面试指南(4)单机数据库、持久化、通知与订阅
25 0
|
1月前
|
NoSQL 安全 Unix
Redis源码、面试指南(4)单机数据库、持久化、通知与订阅(中)
Redis源码、面试指南(4)单机数据库、持久化、通知与订阅
28 0
|
1月前
|
存储 NoSQL API
Redis源码、面试指南(4)单机数据库、持久化、通知与订阅(上)
Redis源码、面试指南(4)单机数据库、持久化、通知与订阅
32 1