Redis 的持久化与过期键

简介

Redis 是使用非常广泛的 Key-Value 内存数据库。因为数据都存放在内存中,所以存取速度非常快。不过,很多情况下我们需要将 Redis 中的数据保存到硬盘中以便做备份。Redis 提供了两种数据持久化方式,分别是 RDB 和 AOP,本文分析这两种方式的使用以及过期键对持久化的影响。

RDB

RDB 指的是将 Redis 数据库在某个时间点的快照保存到磁盘,所生成的 RDB 文件是一个经过压缩的二进制文件,通过这个文件可以还原出 Redis 的数据状态。

创建快照的方式有以下几种:

  • 客户端向 Redis 发送 BGSAVE 命令,Redis 会调用 fork 创建一个子进程,然后子进程负责将快照写入硬盘,而父进程继续处理命令请求。
  • 客户端向 Redis 发送 SAVE 命令,此时 Redis 将开始创建快照,并且在完成之前不再响应其它命令。
  • 用户设置 save 配置选项,比如 save 60 10000,那么从 Redis 最近一次创建快照算起,当 “60 秒内有 10000 次写入” 这个条件被满足时, Redis 就会自动触发 BGSAVE 命令。如果用户设置了多个 save 配置选项,那么当任意一个 save 配置满足时,Redis 就会触发一次 BGSAVE 命令。save 配置的格式如下所示:
save 60 10000
stop-writes-on-bgsave-error no
rdbcompression yes    // 使用压缩
dbfilename dump.rdb  // RBD 文件的名字

dir ./
  • 当 Redis 通过 SHUTDOWN 命令接收到关闭服务器的请求时,或者接收到 TERM命令时,会执行一个 SAVE 命令,并且阻塞所有的客户端,不再执行任何请求。在 SAVE 命令执行结束后关闭服务器。

  • 当一个 Redis 服务器连接另一个 Redis 服务器,并向对方发送 SYNC 命令来开始一次复制操作的时候,如果主服务器没有在执行 BGSAVE 操作,或者主服务器并非刚执行完 BGSAVE,那么主服务器会执行 BGSAVE 命令。

RDB 的主要问题是,如果系统发生崩溃,那么最近一次执行完快照后修改的数据将被丢失。因此,RDB 适合用于即使丢失一部分数据也不会造成影响的应用程序。

AOF

AOF 指的是将所有执行的写命令写到 AOF 文件的末尾,以此来记录数据发生的变化。如果 Redis 想要恢复 AOF 中的数据,只要重新执行一次 AOF 文件中所包含的写命令就可以。

AOF 的配置如下所示:

appendonly yes  // 打开 aof
appendfsync everysec // aof 同步的频率
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100 // 文件大小增长比超过这个值开始自动重写 aof
auto-aof-rewrite-min-size 64mb  // 文件大小超过这个值才可以有可能自动重写 aof

上面的配置中,appendfsync everysec 设置的是同步的频率。应用程序在向硬盘写入数据的时候有 3 个步骤:

  1. 调用 file.write() 向文件写入,此时需要写入的内容被存储到了缓冲区,并不是真正写到硬盘上了。
  2. 操作系统在某个时候将缓冲区的内容写入硬盘,这时数据才真正被持久化了。

操作系统使用以上的文件写入方式是为了提高性能,毕竟硬盘 I/O 操作是比较耗时的。但是,这种方式的缺点在于如果机器崩溃了那么缓冲区的内容将丢失。程序可以使用 file.flush() 来请求操作系统尽快地将缓冲区的内容刷新到硬盘上,不过何时开始执行仍然由操作系统决定。程序也可以命令操作系统将文件同步 ( sync ) 到硬盘,同步操作会阻塞应用程序直到数据被写入硬盘。当同步操作完成后,即使系统出现故障,也不会对被同步的文件造成影响。

对于 Redis 来讲,可以指定 appendfsync 以何种方式让数据完全同步到硬盘,这个配置有 3 个选项:

  1. always: 每个 Redis 写命令都立即同步到硬盘,这是比较消耗性能的
  2. everysec: 每秒执行一次同步,兼顾性能与数据安全,是比较常用的选项
  3. no: 让操作系统决定何时进行同步

always 可以使得在 Redis 发生崩溃时丢失的数据最少,但是也是最消耗性能的,导致 Redis 的处理速度变慢。ererysec 是一种兼顾性能与数据安全的方式,在这种情况下,如果系统崩溃,用户最多会丢失一秒内的数据。no 选项完全将同步交给操作系统被决定,性能也不比 everysec 高多少,是不推荐的方式。

AOF 的缺点是随着 Redis 的不断运行,AOF 文件可能会非常大,甚至用完硬盘的空间。解决这个问题的办法是 AOF 重写。

重写

客户端可以发送 BGREWRITEAOF 命令让 Redis 重写 AOF 文件,Redis 会移除冗余的 AOF 命令进行重写,使得 AOF 文件的体积尽可能地小。

除了客户端主动发送 BGREWRITEAOF 命令,也可以使用配置让 Redis 在满足一定条件地情况下自动开始重写 AOF 文件。例如上一小节设置了 auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb。这两个配置的含义是,如果 AOF 文件大于 64MB 并且比上一次重写之后的大小增加了一倍的时候,Redis 将执行 BGREWERITEAOF 命令。

过期键删除

用户往往为 Redis 中的键设定过期时间,因此需要一定的策略来删除过期键,可以有三种策略:

  1. 定时删除,即通过定时器在过期时间到达的时候删除过期的键。这种方式的优点是节省内存,不会因为大量的过期键占用内存资源,而缺点则是消耗 CPU 资源,尤其是过期键数量较多的时候,删除操作消耗太长时间,降低了 Redis 的响应时间。

  2. 惰性删除,即在每次获取某个键的时候判断是否过期,如果未过期,则正常返回其值,否则删除这个键,返回空。这种方式的优点是节省 CPU 资源,但是消耗了内存。尤其是过期键数量较多的时候,大量内存被无效的键占用,相当于内存泄露。

  3. 定期删除,即每隔一段时间周期对数据库中的键进行扫描,但是只扫描其中一部分,力求在内存和 CPU 之间达到一个平衡。

从上面 3 种策略可以看出,单用第一个肯定是不行的,Redis 的响应时间至关重要。第二个则是比较好的方式,在获取键的时候判断是否过期并决定是否删除,它的缺点是很多键无法及时删除。如果一个过期键再也没有被访问,那么它将永远留在内存中,而第三种方式正好可以弥补。

Redis 中过期键的删除策略正是惰性删除与定期删除的结合。

过期键与持久化

了解了过期键的删除策略后,下面看下键的过期时间对持久化的影响。

在生成 RDB 文件的过程中,如果一个键已经过期,那么其不会被保存到 RDB 文件中。在载入 RDB 的时候,要分两种情况:

  1. 如果 Redis 以主服务器的模式运行,那么会对 RDB 中的键进行时间检查,过期的键不会被恢复到 Redis 中。
  2. 如果 Redis 以从服务器的模式运行,那么 RDB 中所有的键都会被载入,忽略时间检查。在从服务器与主服务器进行数据同步的时候,从服务器的数据会先被清空,所以载入过期键不会有问题。

对于 AOF 来说,如果一个键过期了,那么不会立刻对 AOF 文件造成影响。因为 Redis 使用的是惰性删除和定期删除,只有这个键被删除了,才会往 AOF 文件中追加一条 DEL 命令。在重写 AOF 的过程中,程序会检查数据库中的键,已经过期的键不会被保存到 AOF 文件中。

在运行过程中,对于主从复制的 Redis,主服务器和从服务器对于过期键的处理也不相同:

  1. 对于主服务器,一个过期的键被删除了后,会向从服务器发送 DEL 命令,通知从服务器删除对应的键
  2. 从服务器接收到读取一个键的命令时,即使这个键已经过期,也不会删除,而是照常处理这个命令。
  3. 从服务器接收到主服务器的 DEL 命令后,才会删除对应的过期键。

这么做的主要目的是保证数据一致性,所以当一个过期键存在于主服务器时,也必然存在于从服务器。

总结

本文对 Redis 的两种持久化方式进行了简要的梳理,分析了 Redis 删除过期键的策略以及对持久化的影响。理解了这部分内容不仅可以让我们对 Redis 的使用更加得心应手,对于学习 Redis 的其它内容如复制的过程也会很有帮助。

参考

  • 《Redis 实战》
  • 《Redis 设计与实现》
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,825评论 6 546
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,814评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,980评论 0 384
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 64,064评论 1 319
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,779评论 6 414
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,109评论 1 330
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,099评论 3 450
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,287评论 0 291
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,799评论 1 338
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,515评论 3 361
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,750评论 1 375
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,221评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,933评论 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,327评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,667评论 1 296
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,492评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,703评论 2 380

推荐阅读更多精彩内容

  • 从这篇文章开始,将依次介绍Redis高可用相关的知识——持久化、复制(及读写分离)、哨兵、以及集群。 本文将先说明...
    不变甄心阅读 706评论 0 4
  • 前言 在上一篇文章中,介绍了Redis内存模型,从这篇文章开始,将依次介绍Redis高可用相关的知识——持久化、复...
    Java架构阅读 2,348评论 3 21
  • 一、Redis高可用概述 在介绍Redis高可用之前,先说明一下在Redis的语境中高可用的含义。 我们知道,在w...
    空语阅读 1,608评论 0 2
  • 企业级redis集群架构的特点 海量数据 高并发 高可用 要达到高可用,持久化是不可减少的,持久化主要是做灾难恢复...
    lucode阅读 2,219评论 0 7
  • 在布局文件中给edittext的父控件增加两个属性
    柏林billy阅读 1,624评论 0 1