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

一文理解 Redis 持久化:RDB和AOF(redis持久化机制和如何实现持久化)

mhr18 2024-11-11 12:05 29 浏览 0 评论

1. 概述

我们知道 Redis 是一个内存数据库,也就意味着如果我们的电脑异常重启或者服务器宕机的情况下,存储在 Redis 中的数据会丢失。

Redis 虽然是个内存数据库,但是 Redis 支持 RDBAOF 两种持久化机制,将数据写往磁盘,可以有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化的文件即可实现数据恢复。

RDB(Redis DataBase) 持久化是把当前进程数据生成 快照 保存到硬盘的过程。什么是快照?你可以理解成把当前时刻的数据拍成一张照片保存下来。

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是 默认 的持久化方式,这种方式就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为 dump.rdb

前面说了,RDB 是快照的方式来保存数据的,因此对于 RDB 来说,提供了两种触发机制, 手动触发和自动触发。

手动触发分别对应 savebgsave 命令。

2.1 save

save 命令会阻塞当前 Redis 服务器,直到 RDB 过程完成为止。

因此,对于内存比较大的实例会造成长时间阻塞, 线上环境不建议使用

2.2 bgsave

bgsave 命令执行时,Redis 进程执行 fork 操作创建 的进程 ,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。

显然 bgsave 命令是针对 save 阻塞问题做的优化。因此 Redis 内部所有的涉及 RDB 的操作都采用 bgsave 的方式。其具体流程如下:

  1. 执行 bgsave 命令,Redis 父进程判断当前是否存在正在执行的子进程,如 RDB/AOF 子进程,如果存在,bgsave 命令直接返回。
  2. 父进程执行 fork 操作创建子进程,fork 操作过程中父进程会阻塞,通过 info stats 命令查看 latest_fork_usec 选项,可以获取最近一个 fork 操作的耗时,单位为微秒。
  3. 父进程 fork 完成后, bgsave 命令返回 **Background saving started **信息并不再阻塞进程,可以继续响应其他命令。
  4. 子进程创建 RDB 文件,根据进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行 lastsave 命令可以获取最后一次生成 RDB 的时间,对应 info 统计的 rdb_last_save_time 选项。127.0.0.1:6379> lastsave (integer) 1640574329
  5. 进程发送信号给父进程表示完成,父进程更新统计信息。

2.3 自动触发

除了执行命令手动触发之外,Redis 内部还存在自动触发 RDB 的持久化机制。自动触发是由我们的配置文件来完成的,在 redis.conf 配置文件中,有如下配置:

  • savesave m n,指在 m 秒内,如果有 n 个键发生改变,则自动触发持久化(执行一次 bgsave 命令)。例如,save 60 1 则表明在 60 秒内,至少有一个键发生改变,就会触发 RDB 持久化。
  • stop-writes-on-bgsave-error默认值为 yes。当启用了 RDB 且最后一次后台保存数据失败,Redis 是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了。
  • rdbcompression默认值是 yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。
  • dbfilename设置快照的文件名,默认是 dump.rdb。
  • dir设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名,默认为 ./

2.4 RDB 文件

RDB 生成的持久化文件默认为 dump.rdb ,可在配置文件中设置,也可以通过以下命令查找:

find / -name dump.rdb

# linux 下查找
[root@localhost ~]# find / -name dump.rdb
/usr/local/redis/redis-6.2.6/src/dump.rdb

RDB 文件保存在 dir 配置指定的目录下,文件名通过 dbfilename 配置指定。

可以通过执行 config set dir {newDir}config set dbfilename {newFileName} 运行期动态执行,当下次运行时 RDB 文件会保存到新目录。

Redis 默认采用 LZF 压缩算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。

虽然压缩 RDB 会消耗 CPU,但可大幅降低文件的体积,方便保存到硬盘或通过网维示络发送给从节点,因此线上建议开启。

如果 Redis 加载损坏的 RDB 文件时拒绝启动,并打印如下日志:

# Short read or 0OM loading DB. Unrecoverable error,aborting now.

这时可以使用 Redis 提供的 redis-check-dump 工具检测 RDB 文件并获取对应的错误报告。

2.5 RDB 的优缺点

2.5.1 优点

bgsave

2.5.2 缺点

  1. RDB 方式数据 没办法做到实时持久化/秒级持久化 。因为 bgsave 每次运行都要执行 fork 操作创建子进程,属于重量级操作,频繁执行成本过高。
  2. RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个格式的 RDB 版本,存在老版本 Redis 服务无法兼容新版 RDB 格式的问题。

针对 RDB 不适合实时持久化的问题,Redis 提供了 AOF 持久化方式来解决。

AOF(Append Only File)持久化,以独立日志的方式 记录每次写命令 ,重启时再 重新执行 AOF 文件中的命令 达到恢复数据的目的。

AOF 的主要作用是解决了数据持久化的实时性,目前已经是 Redis 持久化的主流方式。相比 RDB 的全量备份节省了很多时间。

开启 AOF 功能需要设置配置,默认不开启。AOF 文件名通过 appendfilename 配置设置,默认文件名是 appendonly.aof。保存路径同 RDB 持久化方式一致,通过 dir 配置指定。

# 开启 AOF
appendonly yes

# AOF 文件名
appendfilename "appendonly.aof"

# always   每收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
# everysec 每秒强制写入磁盘一次,性能和持久化方面做了折中,推荐
appendfsync everysec

# 正在导出rdb快照的过程中,要不要停止同步aof
no-appendfsync-on-rewrite  yes

# aof文件大小比起上次重写时的大小,增长率100%时,重写
auto-aof-rewrite-percentage 100

# aof文件,至少超过64M时,重写
auto-aof-rewrite-min-size 64mb

3.1 工作流程

AOF 的工作流程如下:

  1. 命令写入(append)所有的写入命令会追加到 aof_buf(缓冲区)中。
  2. 文件同步(sync)AOF 缓冲区根据对应的策略向硬盘做同步操作。
  3. 文件重写(rewrite)随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
  4. 重启加载(load)当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。

3.2 命令写入

AOF 命令写入的内容直接是 RESP 文本协议格式。例如 set hello world 这条命令,在 AOF 缓冲区会追加如下文本:

* 3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n

AOF 为什么直接采用文本协议格式?

文本协议具有很好的兼容性。开启 AOF 后,所有写入命令都包含追加操作,直接采用协议格式,避免了二次处理开销。文本协议具有可读性,方便直接修改和处理。

AOF 为什么把命令追加到 aof_buf 中?

Redis 使用单线程响应命令,如果每次写 AOF 文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载。先写入缓冲区 aof_buf 中,还有另一个好处,Redis 可以提供多种缓冲区同步硬盘的策略,在性能和安全性方面做出平衡。

3.3 文件同步

Redis 提供了多种 AOF 缓冲区同步文件策略,由参数 appendfsync 控制。主要有以下三种:

  1. always命令写入 aof_buf 后调用系统 fsync 操作同步到 AOF 文件,fsync 完成后线程返回命令 fsync 同步文件。配置为 always 时,每次写入都要同步 AOF 文件,在一般的 SATA 硬盘上,Redis 只能支持大约几百 TPS 写入,显然跟 Redis 高性能特性背道而驰,不建议配置。
  2. everysec写人 aof_buf 后调用系统 write 操作,write 完成后线程返回。操作由专门线程每秒调用一次 fsync 命令。配置为 everysec, 是建议的同步策略 ,也是默认配置,做到兼顾性能和数据安全性。理论上只有在系统突然宕机的情况下丢失 1 秒的数据。
  3. no写入 aof_buf 后调用系统 write 操作,不对 AOF 文件做 fsync 同步,同步硬盘操作由操作系统负责,通常同步周期最长 30 秒。配置为 no,由于操作系统每次同步 AOF 文件的周期不可控,而且会加大每次同步硬盘的数据量,虽然提升了性能,但数据安全性无法保证。

系统调用 write 和 fsync

write

操作会触发延迟写(delayed write)机制。Linux 在内核提供页缓冲区用来提高硬盘 IO 性能。write 操作在写入系统缓冲区后直接返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区页空间写满或达到特定时间周期。同步文件之前,如果此时系统故障宕机,缓冲区内数据将丢失。

fsync

针对单个文件操作(比如 AOF 文件),做强制硬盘同步,fsync 将阻塞直到写入硬盘完成后返回,保证了数据持久化。

3.4 文件重写

随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引入 AOF 重写机制压缩文件体积。AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新 AOF 文件的过程。

重写后的 AOF 文件为什么可以变小?原因如下:

  1. 进程内已经超时的数据不再写入文件。
  2. 旧的 AOF 文件含有无效命令,如 set a 111、set a 222 等。重写使用进程内数据直接生成,这样新的 AOF 文件只保留最终数据的写入命令。
  3. 多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush listc 可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢出,对于 list、set、hash、zset 等类型操作,以 64 个元素为界拆分为多条。

AOF 重写降低了文件占用空间,除此之外,另一个目的是:更小的 AOF 文件可以更快地被 Redis 加载。

AOF 重写过程可以手动触发和自动触发:

  • 手动触发:直接调用 bgrewriteaof 命令。该命令会将内存中的数据以命令的方式保存到临时文件中,同时会 fork 出一条新进程来将文件重写。
  • 自动触发:根据 auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage 参数确定自动触发时机。auto-aof-rewrite-min-size auto-aof-rewrite-percentage

3.5 重启加载

AOF 和 RDB 文件都可以用于服务器重启时的数据恢复。redis 重启时加载 AOF 与 RDB 的顺序是怎么样的呢?

  1. 当 AOF 和 RDB 文件同时存在时,优先加载 AOF;
  2. 若关闭了 AOF,加载 RDB 文件;
  3. 加载 AOF/RDB 成功,redis 重启成功;
  4. AOF/RDB 存在错误,启动失败打印错误信息。

3.6 AOF 的优缺点

3.6.1 优点

  1. AOF 可以更好的保护数据不丢失,一般 AOF 会每隔 1 秒,通过一个后台线程执行一次 fsync 操作,最多丢失 1 秒钟的数据;
  2. AOF 日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损;
  3. AOF 日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写;
  4. AOF 日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用 flushall 命令清空了所有数据,只要这个时候后台 rewrite 还没有发生,那么就可以立即拷贝 AOF 文件,将最后一条 flushall 命令给删了,然后再将该 AOF 文件放回去,就可以通过恢复机制,自动恢复所有数据。

3.6.2 缺点

  1. 对于同一份数据来说,AOF 日志文件通常比RDB数据快照文件更大。
  2. AOF 开启后,支持的写 QPS 会比 RDB 支持的写 QPS 低,因为 AOF 一般会配置成每秒 fsync 一次日志文件,当然,每秒一次 fsync,性能也还是很高的。
  3. 以前 AO F发生过 bug,就是通过 AOF 记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。

4. 如何选择

对于 RDB,它能够在指定的时间间隔对内存中的数据进行快照存储。

对于 AOF,他能记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF 命令以文本协议追加保存每次写的操作到文件末尾。Redis 还能够对 AOF 文件进行后台重写,使 AOF 文件体积不至于过大。

两种方式同时开启,在两种方式同时开启的情况下,Redis 启动的时候会优先加载 AOF 文件来恢复原始数据,因为在通常情况下 AOF 文件保存的数据集比 RDB 文件保存的数据集要完整,RDB 的数据会不实时。

那么只使用 AOF 呢?建议不要,因为 RDB 更适合用于备份数据库(AOF 在不断变化,不好备份),快速重启,而不会有 AOF 可能存在的潜在 bug,留着作为一个补救的手段。

当然,如果你只是用作缓存,只希望数据在程序运行的时候存在,那么就可以不使用任何持久化方式。

选项

RDB

AOF

启动优先级

体积

恢复速度

数据安全

丢数据

三种策略

附:配置文件详解

# redis进程是否以守护进程的方式运行,yes为是,no为否(不以守护进程的方式运行会占用一个终端)。
daemonize no
# 指定redis进程的PID文件存放位置
pidfile /var/run/redis.pid
# redis进程的端口号
port 6379
#是否开启保护模式,默认开启。要是配置里没有指定bind和密码。开启该参数后,redis只会本地进行访问,拒绝外部访问。要是开启了密码和bind,可以开启。否则最好关闭设置为no。
protected-mode yes
# 绑定的主机地址
bind 127.0.0.1
# 客户端闲置多长时间后关闭连接,默认此参数为0即关闭此功能
timeout 300
# redis日志级别,可用的级别有debug.verbose.notice.warning
loglevel verbose
# log文件输出位置,如果进程以守护进程的方式运行,此处又将输出文件设置为stdout的话,就会将日志信息输出到/dev/null里面去了
logfile stdout
# 设置数据库的数量,默认为0可以使用select <dbid>命令在连接上指定数据库id
databases 16
# 指定在多少时间内刷新次数达到多少的时候会将数据同步到数据文件
save <seconds> <changes>
# 指定存储至本地数据库时是否压缩文件,默认为yes即启用存储
rdbcompression yes
# 指定本地数据库文件名
dbfilename dump.db
# 指定本地数据问就按存放位置
dir ./
# 指定当本机为slave服务时,设置master服务的IP地址及端口,在redis启动的时候他会自动跟master进行数据同步
replicaof <masterip> <masterport>
# 当master设置了密码保护时,slave服务连接master的密码
masterauth <master-password>
# 设置redis连接密码,如果配置了连接密码,客户端在连接redis是需要通过AUTH<password>命令提供密码,默认关闭
requirepass footbared
# 设置同一时间最大客户连接数,默认无限制。redis可以同时连接的客户端数为redis程序可以打开的最大文件描述符,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回 max number of clients reached 错误信息
maxclients 128
# 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key。当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
maxmemory<bytes>
# 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no。
appendonly no
# 指定跟新日志文件名默认为appendonly.aof
appendfilename appendonly.aof
# 指定更新日志的条件,有三个可选参数 - no:表示等操作系统进行数据缓存同步到磁盘(快),always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全), everysec:表示每秒同步一次(折衷,默认值);
appendfsync everysec

相关推荐

软考架构师-案例分析之Redis(软考架构师真题)

软考架构师考试中,Redis的知识考了很多回,从最近几年来看,案例分析经常考,有的时候单独考,有的时候和其他知识点一起考。Redis过往的考试中,考过的知识如下:1、Redis特点,涉及数据类型、持久...

揭秘:视频播放网站如何精准记录用户观看进度

在互联网蓬勃发展的当下,视频内容已毫无争议地成为人们获取信息、享受娱乐休闲时光的核心方式。据权威数据统计,全球每天有数十亿小时的视频被观看,视频流量在网络总流量中的占比逐年攀升,预计在未来几年内将超过...

量子级一致性!Flink+Redis全局状态管理

百万级实时计算任务如何实现亚毫秒级状态访问?本文揭秘Flink+Redis的量子纠缠态状态管理方案,将状态延迟降至0.3ms。引子:实时风控系统的量子跃迁//传统Flink状态管理(基于RocksD...

在 Mac 上运行 Redis 的 Docker 容器

在Mac上运行Redis的Docker容器,你可以按以下步骤操作,非常简单高效:一、前提要求已安装DockerDesktopforMac可通过终端验证Docker是否可用:d...

从 0 到 1:使用 Nginx + Lua 打造高性能 Web 网关

在大规模分布式架构中,Web网关扮演着重要角色,负责请求转发、负载均衡、限流、认证等功能。而Nginx+Lua结合可以提供:o高性能:Nginx是目前最流行的高性能Web服务器o动...

外贸独立站缓存设置黑科技:用错Redis比没缓存更致命

上周帮一个杭州卖家排查网站崩溃问题,发现这老铁把Redis缓存设置成128MB还开着持久化,服务器内存直接炸得比春节红包还彻底——"你这哪是缓存啊,根本是DDoS攻击自己!"最近Clo...

Spring Boot3 整合 Redis,这些缓存注解你真的会用吗?

你在开发SpringBoot3项目时,有没有遇到过这样的困扰?随着项目功能不断增加,数据量逐渐庞大,接口响应速度变得越来越慢,用户体验直线下降。好不容易找到优化方向——引入Redis缓存...

MySQL处理并发访问和高负载的关键技术和策略

MySQL处理并发访问和高负载的关键技术和策略主要包括以下几个方面:一、硬件优化1.CPU:提升CPU处理能力可以明显改善并发处理性能。根据数据库负载,考虑使用更多的CPU核心。2.内存:增加内存可以...

druid解决高并发的数据库(druid多数据源配置 spring boot)

处理高并发的时候可以解决我们java一个核心问题java核心问题就是并发问题解决并发一个是redis一个是线程池的方式现在出来是个druid好像现在解决高并发的方式进行更换数据库的方式操作场景插入频繁...

高并发方案最全详解(8大常见方案)

关注△mikechen△,十余年BAT架构经验倾囊相授!大家好,我是mikechen睿哥。高并发是大型架构的核心,下面我重点来详解常见8大高并发方案@mikechen文章来源:mikechen.cc分...

MySQL如何处理并发访问和高负载?(mysql如何处理并发访问和高负载访问)

MySQL在处理并发访问和高负载方面,采取了一系列关键技术和策略,以确保数据库系统在面对不断增长的并发需求时维持高效和稳定的性能。以下是对这些技术和策略的详细阐述,旨在全面解析MySQL如何处理并发访...

Redis高可用集群详解(redis高可用方案以及优缺点)

Redis集群与哨兵架构对比Redis哨兵架构在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具监控master节点状态,如果master节点异常,则会做主从切换,将某一台sla...

MCP协议重大升级!Spring AI联合阿里Higress,性能提升300%

引言:一场颠覆AI通信的技术革命2025年3月,MCP(ModelContextProtocol)协议迎来里程碑式升级——StreamableHTTP正式取代HTTP+SSE成为默认传输层。这一...

阿里三面被挂,幸获内推,历经5轮终于拿到口碑offer

作者:Java程序猿阿谷来源:https://www.jianshu.com/p/1c8271f03aa5每一个互联网人心中都有一个大厂梦,百度、阿里巴巴、腾讯是很多互联网人梦寐以求的地方,而我也不例...

来瞧瞧阿里一面都面些什么(笔试+机试)

絮叨说实话,能有机会面一下阿里对我来说帮助确实有蛮多,至少让我知道了自己的不足在哪,都说面试造火箭,上班拧螺丝。但就算是如此,为了生存,你也只有不停的学习,唯有光头,才能更强。哈哈起因2月28日在Bo...

取消回复欢迎 发表评论: