前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis 的 AOF 和 RDB

Redis 的 AOF 和 RDB

作者头像
Meteors
发布2021-12-08 20:21:24
1.1K0
发布2021-12-08 20:21:24
举报
文章被收录于专栏:星空畅想

Redis 对于开发的同学都不陌生,它是当下最流行的键值(Key-Value)数据库,作为一种高性能的数据库,Redis将自己的数据存储在内存中而非磁盘,这就导致如果不想办法将存储在内存中的数据保存到磁盘里面,一旦服务器进程退出(服务宕机),内存中的数据也会一并丢失。

为了解决这个问题,Redis提供了两种持久化数据的方式,也就是我们常说的AOF和RDB。前者是利用AOF(Append only file)文件来记录Redis对数据的写操作,一旦出现进程退出的情况,数据会按照AOF文件的写操作自动恢复Redis;后者是利用RDB(Redis Database)二进制文件保存数据库状态,在进程退出后将读这个二进制文件来达到恢复数据数据的目的,本文主要总结一下这两种持久化方式并简述其原理。

AOF 持久化

简单来说,AOF持久化指的是通过保存Redis服务器所执行的写命令来记录数据库状态,如:

代码语言:javascript
复制
redis> SET msg "hello"
OK
复制代码

使用AOF后可以打开文件看下,内容类似于:

代码语言:javascript
复制
*2\r\n$6\r\nSELECT\r\n$1\r\n0\r\n
*3\r\n$3\r\nSET\r\n$3\r\nmsg\r\n$5\r\nhello\r\n
复制代码

在这个AOF文件中,除了用于制定数据库的SELECT是服务器自动添加的之外,其他都是我们通过客户端发送的命令。其中,*3代表当前命令有三个部分,每个部分都是由+数字开头,后面跟着键、值或命令。这里的数字表示键、值或命令有多少字节,例如 3\r\nSET 代表这个命令有三个字节,

AOF写入与同步

Redis的服务器进程就是一个事件循环,在这个循环中,文件事件负责接收客户端的命令请求,以及向客户端发送命令回复;因为服务器在处理文件事件时可能会执行写命令,使得一些内容被追加到aof_buf缓冲区里面,所以在服务器每次结束一个事件循环之前,都会调用flushAppendOnlyFile函数,考虑是否要将aof_buf缓冲区的内容写入和保存到AOF文件中。所以,AOF不会阻塞文件的写操作

不过,AOF也有个显著的问题:如果在aof_buf缓冲区内容写到AOF文件时,发生服务器宕机,那么这些写操作就会永久消失,为了解决类似的问题,Redis提供了三种写回策略:

appendfssync

函数行为

always

每个事件循环都要将aof_buf缓冲区中所有内容写入到AOF文件中,并且同步AOF文件

everysec

每个事件循环都要将aof_buf缓冲区中所有内容写入到AOF文件中,并且每隔1s就要在子线程中对AOF文件进行一次同步

no

每个事件循环都要将aof_buf缓冲区中所有内容写入到AOF文件中,同步时机需要系统控制

总结AOF的写回策略:

配置项

写回时机

优点

缺点

always

同步写回

可靠性高,基本不丢失

每次都同步导致影响很大

everysec

每秒写会

性能适中

一旦服务退出,则会损失1s内数据

no

操作系统写回

性能好

一旦服务退出,则会损失未写入的全部数据

如果要保证可靠性,那么就选择always或everysec,如果要保证高性能,推荐选择no,写回策略总是根据需求变更的。

AOF文件载入与数据还原

一旦进程退出,就需要根据AOF载入命令并写回数据库,来还愿数据库状态:

未命名文件.png
未命名文件.png

以上面的例子来说,服务器首先读入并执行SELECT 0,之后执行SET msg "hello",服务器的数据库就被还原到之前的状态了,非常简单。

AOF重写

因为AOF持久化是通过保存被执行的写命令来记录数据库状态,随着AOF文件的内容越来越多,文件的体积也会越来越大;随着AOF文件体积的越来越大,还原的时间也随之加长,为了解决AOF体积膨胀的问题,Redis提供了AOF文件重写的功能,通过AOF重写,Redis可以创建一个新的AOF文件来替代现有的AOF文件,同时新的AOF文件通常会比旧的小很多。 那么AOF是怎么实现文件的重写的呢?我们可以简单看一个例子:

代码语言:javascript
复制
redis> SADD colors "red"  // {red}
(integer) 1

redis> SADD colors "yellow" "blue" // {red, yellow, blue}
(integer) 3

redis> SREM colors "red" // {yellow, blue}
(integer) 1

redis> SADD colors "orange" // {yellow, blue, orange}
(integer) 3
复制代码

为了记录这样一条命令,需要写入四次AOF文件;如果可以从Redis读取colors的值,用一条SADD colors "yellow" "blue" "orange"来替代,所需要的命令就可以从四条减少为一条。从数据库中读取键所对应的值,然后用一条命令去记录键值对,替代之前记录这个键值对的多条命令,这就是AOF重写功能的原理。同时,AOF日志重写是通过后台子进程重写,不会阻塞主进程,具体过程各位同学可以自行探究~

RDB 持久化

RDB也被人称为内存快照,RDB 持久化产生的RDB文件是经过压缩的二进制文件,功过该文件可以还愿生成RDB文件时的数据库状态。

未命名文件 (1).png
未命名文件 (1).png

RDB文件是存储在磁盘上的,即使进程退出,只要RDB文件存在,Redis就可以利用RDB来还原数据库(自动还原)。

RDB文件的创建

Redis生成RDB文件有两种方式,一种是 SAVE,另一种是 BGSAVE,两种方式区别如下: 1、SAVE命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求; 2、BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,父进程继续处理命令请求; 另外,如果Redis同时启动了AOF持久化和RDB持久化,服务器会优先使用AOF文件来还原数据库状态;只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数据库状态,要注意这个问题哦~

自动间隔性保存

因为BGSAVE命令可以在不阻塞服务器进程的情况下执行,所以Redis允许用户配置save选项,让服务器每隔一段时间自动执行一次BGSAVE命令,举个例子:

代码语言:javascript
复制
save 900 1
save 300 10
save 60 1000
复制代码

那么只要满足三个条件中任意一个,BGSAVE就会被执行: 1、服务器在900秒之内,对数据库进行了至少1次修改; 2、服务器在300秒之内,对数据库进行了至少10次修改; 3、服务器在60秒之内,对数据库进行了至少1000次修改。

混合使用

Redis4.0支持混合使用AOF文件和RDB来对Redis进行恢复,总结来说就是:在两次RDB文件创建之间,使用AOF文件来记录Redis写入的命令,通过这种方式,可以避免两次RDB写入的时候造成之间记录的数据丢失,以及只使用AOF文件导致AOF文件过大的问题,“成年人的世界就是「我全都要」”。

总结

通过Redis的AOF持久化和RDB持久化可以避免进程退出导致的数据丢失问题,当然使用什么方式一定要结合业务的特性,使用Redis的新特性也可以取长补短,两种方式结合,不妨可以试试

参考

  • 《Redis入门指南》
  • 《Redis设计与实现》
  • 《Redis核心技术与实践》
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年06月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • AOF 持久化
    • AOF写入与同步
      • AOF文件载入与数据还原
        • AOF重写
        • RDB 持久化
          • RDB文件的创建
            • 自动间隔性保存
            • 混合使用
            • 总结
            • 参考
            相关产品与服务
            云数据库 Redis
            腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档