百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

《Redis核心技术与实战》学习总结(四)——Redis的持久化机制

mhr18 2024-11-04 12:48 32 浏览 0 评论

Redis的持久化机制

一旦Redis服务器宕机,内存中的数据会全部丢失。如果单靠从后端DB中恢复,一来会给DB带来巨大的压力,二来从DB拉取数据性能较低会导致应用程序响应变慢。因此,Redis的数据持久化很重要,而且不能从后端DB中恢复。

Redis提供的数据持久化机制只要包括两个:

  • AOF(Append Only File)日志
  • RDB 快照

在Redis 4.0之后,新增了混合持久化机制,它将AOF 和 RDB的优点结合了起来。

AOF日志

所谓AOF,即Append Only File,意思是只会追加写的文件。在Redis中,AOF日志最大的特点就是写后日志,即Redis执行命令将数据写入内存后才记录日志。

延伸:MySQL使用的是WAL日志,即Write Ahead Log 写前日志。例如redo log,它记录的是修改后的数据。不过,AOF却是记录的命令,这些命令是以文本形式保存的。

AOF中存了什么东西?

刚刚说到,AOF记录的是Redis接收的命令,这些命令都是以文本形式保存的。

例如,下图展示了一个AOF日志的内容:

解读:"*3" 表示命令由三个部分组成,"$3 set"表示这部分有三个字节,即"set"命令有三个字节。同理,后续"$7 testkey"表示该部分有七个字节,即"testkey"命令有七个字节。第三部分同理,不再赘述。

AOF的优点是什么?

Redis在向AOF中记录日志时,为了避免额外的开销,不会对写入的命令进行语法检查。因此,如果采用先写日志方式,那么日志中就有可能会记录错误的命令,导致Redis在使用AOF恢复数据的时候,可能会出错。

因此,AOF采用后写日志,只有命令成功执行之后才会被记录到日志中。否则,系统就会向客户端报错。所以,AOF的优点主要就在于可以避免记录错误命令的情况,并且由于是写后日志,因此它也不会阻塞当前的写操作

AOF的缺点是什么?

AOF有两个潜在的风险点:

一是如果将Redis作为DB用的话(当然一般情况很少这样选型),如果某个命令因为服务器宕机没有记入日志,那么Redis无法用AOF日志进行数据恢复。换句话说,Redis接收的命令及其相应数据有丢失的风险

二是如果在写AOF日志到磁盘时磁盘写压力过大,会导致写盘很慢,由于AOF日志也是在主线程中执行,因此可能会导致后续的操作无法执行。换句话说,AOF日志可能会给下一个操作带来阻塞的风险

如何规避AOF的潜在风险?

从刚刚的介绍中可以了解到,AOF的两个潜在的风险点都和AOF写回磁盘的时机有关,换句话说,要想规避风险,只要能控制一个写命令执行完成后AOF日志写回磁盘的时机 就能解决。

在Redis中,AOF机制提供了三个配置项供我们选择:

(1)Always,即同步写回:每个命令执行完,立马同步将日志写到磁盘;

画外音>此选项可以做到基本不丢数据,但是性能较差,会影响主线程性能。

(2)Everysec,即每秒写回:每个命令执行完,只是先将日志写到AOF文件的内存缓冲区,每隔一秒钟再把缓冲区中的内容写到磁盘;

画外音>此选项可以减少对主线程性能的影响,但是如果发生宕机,仍然存在命令操作丢失的风险。

(3)No,即不主动控制何时写回,由操作系统来控制写回:每个命令执行完,先将日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区的内容写回磁盘。

画外音>此选项性能较好,但回收策略就变成了黑盒子,且宕机时可能会出现数据丢失较多的风险。

这三种写回时机策略的优缺点总结在下图中:

可以看到,这三种策略在可靠性上是从高到低,而在性能上则是从低到高。这和关系型数据库的隔离级别项是类似的,安全性越高,则性能越低。

一般情况下,允许数据有一点丢失,又希望性能还不错的话,请选择Everysec策略。这也是系统设计中最常见的原则-trade off(权衡取舍),我们需要在多个指标之间做取舍。

如何保持Redis的高性能?

我们都知道Redis具有较高的性能,那么,对于AOF日志来说,它是否有可能拖累Redis性能?答案是可能的,如果写入的日志文件过大,就有可能拖累性能。

Note:日志文件过大不仅对写回磁盘时造成性能影响,在使用日志进行故障恢复时也有影响。因为,Redis的单线程设计,日志中的命令只能一条一条按顺序执行,“重放”过程会变慢。

那么,日志文件过大该怎么破?

AOF提供了重写机制,即如果AOF需要一次记录的命令太多,Redis会进行重写:Redis根据现状创建一个新的AOF文件,它会读取所有键值对,然后对每一个键值对用一条命令记录它的写入。

换句话说,重写机制就是在给AOF日志文件做瘦身,具体实现其实就是将旧日志中的多条命令换成一条新的命令,即“多变一”。下图就展示了这样的一个实例:

从上图中可以看出,重写后的日志较旧日志节省了好几条命令的空间,这对于有可能会被修改成百上千次的key/value来说,能节省的空间当然就更大了。

其次,AOF的重写机制是由后台子进程(bgrewriteaof)来执行的,它不会影响主线程,进而避免阻塞主线程导致性能下降。

AOF的非阻塞重写过程如下图所示:

从上图中可以看出,当AOF重写的时候Redis会先fork出一个后台子进程,它会执行一次内存拷贝用于接下来的重写。然后,Redis会使用两个日志(正在使用的AOF日志 和 新的AOF重写日志)来保证在重写过程中,新写入的数据不会丢失。

用蒋德钧老师的八个字概括AOF重写的过程:“一个拷贝,两处日志”。

AOF重写何时被触发?

在Redis中,有两个配置项在控制AOF重写的触发时机。

如果AOF文件大小同时超出下面这两个配置项时,会自动触发AOF重写。

auto-aof-rewrite-min-size: 
表示运行AOF重写时文件的最小大小,默认为64MB
auto-aof-rewrite-percentage: 
表示比上次重写后的日志文件体量增加了多少百分比,默认为100%

RDB内存快照

RDB(Redis DataBase)内存快照是Redis提供的第二个持久化机制,它既能避免数据丢失,又能更快地恢复数据。

所谓内存快照,就是指内存中的数据在某一个时刻的状态记录,它类似于照片。在Redis中,这些照片是就后缀为RDB的文件。

与AOF的对比

与AOF相比,RDB记录的是某一个时刻的数据(二进制的形式)而不是操作命令,因此,在做数据恢复的时候,我们可以直接将RDB文件读入内存就可以完成恢复。

这样一来,就可以避免AOF的缺点:需要按照顺序逐一重新执行操作命令所带来的低效的性能问题。

画外音>但是内存快照也并不是最优选项。

全量快照与增量快照

当Redis中数据并不多时,我们可以直接做RDB的全量快照,这样一次性就记录了所有的数据,一个都不少。

但是,当数据量越来越大之后,做全量快照的过程中写入磁盘的时间会逐渐增大,全量数据越多,RDB文件就会越大,往磁盘上写数据的时间开销也就越大。

因为,Redis的单线程模型(这里仅探讨6.0之前的Redis单线程版本)决定了开发者需要避免阻塞主线程的所有操作。当全量数据越大,RDB快照的写入操作就越有概率会阻塞主线程。

因此,Redis也提供了增量快照,即一次全量快照之后,后续的快照只需要对修改的数据进行快照记录,就可以避免每次全量快照的开销。

RDB文件如何生成?

Redis提供了两个命令 save 和 bgsave 来生成RDB文件,其中:

(1)save 在主线程上执行,会导致主线程阻塞;(不建议使用)

(2)bgsave 会在一个后台子进程中专门用于写入RBD文件,它不会引起主线程阻塞;(它也是Redis RDB生成的默认配置

画外音>为什么是子进程而不是子线程?因为Redis就是一个进程,而且是一个只有单线程的进程,一般也将其单线程称为主线程。

下图展示了bgsave的执行过程:

因此,我们可以通过bgsave命令来做全量快照操作。

RDB做快照时数据能修改吗?

刚刚提到,RDB做快照和拍照类似,当你拍照的时候,也是希望在那一瞬间不希望被拍的人乱动。数据,也是同理。

但是,如果在给数据做快照时,数据不能被修改,那无疑等同于停服,会给业务造成一定影响。

幸运的是,Redis早已经帮我们想好了这个问题,Redis借助了OS提供的写时复制(Copy-On-Write, COW)技术,支持在执行RDB快照生成的期间,正常处理写操作

下面通过一幅图来介绍COW技术:

总结一下,Redis支持快照期正常处理写操作大概有两个核心步骤:

(1)如果主线程是读取操作,那么主线程和bgsave子进程互不影响;

(2)如果主线程是修改操作,那么主线程打算修改一个key/value时,这个数据就会生成一个副本,主线程会对这个副本进行修改(而不是原来的位置)。同时,bgsave子进程可以把原来位置的数据继续写入RDB文件。

有了这两个核心步骤,Redis在生成RBD文件时既保证了数据完整性,同时又允许对数据做修改,还避免了对正常业务的影响。

多久做一次快照合适?

和拍照类似,“连拍”可以抓住某一时刻连续的单个场景。对数据而言,也是如此,如果快照的间隔变短,那么丢失的数据量也不会很多。

那么,问题来了,多久做一次RDB快照比较合适?

首先,我们需要有一个基本认知:虽然bgsave不会阻塞主线程,但是如果频繁地执行全量快照,也会带来一定的性能问题

(1)频繁执行全量快照,磁盘压力会变大!因为,多个快照会竞争优先的磁盘带宽,前一个快照还没有做完,后一个又开始了...

(2)虽然bgsave本身不会阻塞主线程,但是fork这个bgsave的创建过程会阻塞主线程!

其次,我们在一次全量快照之后即可做多次增量快照,因此这里说的快照频率一般情况下是指增量快照的间隔时间。

最后,在增量快照操作的间隔期间,Redis需要记住哪些数据被修改了,这也会带来额外的空间开销问题,如下图所示:

因此,虽然RDB较AOF具有恢复速度快的优点,但是快照的频率不太好控制,因此如果频率太低,两次快照之间可能会有较多数据丢失的风险;如果频率太高,会产生较多额外的开销。

混合持久化

在Redis 4.0之后,新增了混合持久化机制,它将AOF 和 RDB的优点结合了起来。

Note:

Redis 4.0通过以下配置即可开启混合持久化(前提条件:先开启AOF):

# aof‐use‐rdb‐preamble yes

Redis 5.0及之后已经默认开启了混合持久化,使用以下命令可以验证:

> config get aof-use-rdb-preamble
1) "aof-use-rdb-preamble"
2) "yes"

简单来说,它的执行策略包括以下两个核心步骤:

(1)RDB内存快照以一定的频率执行

(2)在两次快照之间使用AOF记录所有的修改命令操作

混合持久化的执行过程也可以用一幅图展现:

那么,它所具有的优势也就体现了出来:

(1)不用频繁地生成快照,避免频繁fork子进程操作对主线程的影响;

(2)AOF日志只用于两次快照间的命令记录,不需记录所有操作,即避免了日志文件过大,也避免了重写的开销。

如此,它就有点“鱼和熊掌兼得”的味道,即利用了RDB文件的快速恢复性 + AOF只记录操作命令的简单性。它也成为了Redis 5.0及之后版本的默认持久化选项。

End总结

本文总结了Redis持久化的几个核心要点:

(1)AOF是啥,其机制的优缺点

(2)RDB是啥,其机制的优缺点

(3)混合持久化又是啥

关于如何选择持久化方式,蒋德钧老师给出了几点建议:

(1)当数据不能丢失时(即可靠性要求很高的场景),建议使用混合持久化机制;

(2)当允许数据丢失分钟级时,可以只使用RDB快照;

(3)如果一定要只使用AOF,优先使用Everysec配置,因为它在可靠性和性能之间取得了一个平衡;


参考资料

极客时间,蒋德钧《Redis核心技术与实战》

黄建宏,《Redis设计与实现》

拉钩教育,刘海丰《架构设计面试精讲》

作者:Edison Zhou

相关推荐

Docker安装详细步骤及相关环境安装配置

最近自己在虚拟机上搭建一个docker,将项目运行在虚拟机中。需要提前准备的工具,FinallShell(远程链接工具),VM(虚拟机-配置网络)、CentOS7(Linux操作系统-在虚拟机上安装)...

Linux下安装常用软件都有哪些?做了一个汇总列表,你看还缺啥?

1.安装列表MySQL5.7.11Java1.8ApacheMaven3.6+tomcat8.5gitRedisNginxpythondocker2.安装mysql1.拷贝mysql安装文件到...

Nginx安装和使用指南详细讲解(nginx1.20安装)

Nginx安装和使用指南安装1.检查并安装所需的依赖软件1).gcc:nginx编译依赖gcc环境安装命令:yuminstallgcc-c++2).pcre:(PerlCompatibleRe...

docker之安装部署Harbor(docker安装hacs)

在现代软件开发和部署环境中,Harbor作为一个企业级的容器镜像仓库,提供了高效、安全的镜像管理解决方案。通过Docker部署Harbor,可以轻松构建私有镜像仓库,满足企业对镜像存储、管理和安全性...

成功安装 Magento2.4.3最新版教程「技术干货」

外贸独立站设计公司xingbell.com经过多次的反复实验,最新版的magento2.4.3在oneinstack的环境下的详细安装教程如下:一.vps系统:LinuxCentOS7.7.19...

【Linux】——从0到1的学习,让你熟练掌握,带你玩转Linu

学习Linux并掌握Java环境配置及SpringBoot项目部署是一个系统化的过程,以下是从零开始的详细指南,帮助你逐步掌握这些技能。一、Linux基础入门1.安装Linux系统选择发行版:推荐...

cent6.5安装gitlab-ce最新版本-11.8.2并配置邮件服务

cent6.5安装gitlab-ce最新版本-11.8.2并配置邮件服务(yum选择的,时间不同,版本不同)如果对运维课程感兴趣,可以在b站上搜索我的账号:运维实战课程,可以关注我,学习更多免费的运...

时隔三月,参加2020秋招散招,终拿字节跳动后端开发意向书.

3个月前头条正式批笔试4道编程题只AC了2道,然后被刷了做了200多道还是太菜了,本来对字节不抱太大希望,毕竟后台竞争太大,而且字节招客户端开发比较多。后来看到有散招免笔试,抱着试一试的心态投了,然而...

Redisson:Java程序员手中的“魔法锁”

Redisson:Java程序员手中的“魔法锁”在这个万物互联的时代,分布式系统已经成为主流。然而,随着系统的扩展,共享资源的争夺成为了一个棘手的问题。就比如你想在淘宝“秒杀”一款商品,却发现抢的人太...

【线上故障复盘】RPC 线程池被打满,1024个线程居然不够用?

1.故障背景昨天晚上,我刚到家里打开公司群,就看见群里有人讨论:线上环境出现大量RPC请求报错,异常原因:被线程池拒绝。虽然异常量很大,但是异常服务非核心服务,属于系统旁路,服务于数据核对任务,即使...

小红书取消大小周,有人不高兴了!

小红书宣布五一节假日之后,取消大小周,恢复为正常的双休,乍一看工作时长变少,按道理来说大家应该都会很开心,毕竟上班时间缩短了,但是还是有一些小红书的朋友高兴不起来,心情很复杂。因为没有了大小周,以前...

延迟任务的多种实现方案(延迟机制)

场景订单超时自动取消:延迟任务典型的使用场景是订单超时自动取消。功能精确的时间控制:延时任务的时间控制要尽量准确。可靠性:延时任务的处理要是可靠的,确保所有任务最终都能被执行。这通常要求延时任务的方案...

百度java面试真题(java面试题下载)

1、SpingBoot也有定时任务?是什么注解?在SpringBoot中使用定时任务主要有两种不同的方式,一个就是使用Spring中的@Scheduled注解,另一个则是使用第三方框架Q...

回归基础:访问 Kubernetes Pod(concurrent.futures访问数据库)

Kubernetes是一头巨大的野兽。在它开始有用之前,您需要了解许多概念。在这里,学习几种访问集群外pod的方法。Kubernetes是一头巨大的野兽。在它开始有用之前,您需要了解许多不同的...

Spring 缓存神器 @Cacheable:3 分钟学会优化高频数据访问

在互联网应用中,高频数据查询(如商品详情、用户信息)往往成为性能瓶颈。每次请求都触发数据库查询,不仅增加服务器压力,还会导致响应延迟。Spring框架提供的@Cacheable注解,就像给方法加了一...

取消回复欢迎 发表评论: