首页 > 数据库 >Redis持久化底层原理详解

Redis持久化底层原理详解

时间:2022-12-21 11:36:19浏览次数:40  
标签:AOF aof Redis 详解 文件 RDB 重写 底层


Redis持久化

由于 Redis 是一个内存数据库,所谓内存数据库,就是将数据库中的内容保存在内存中,这与传统的MySQL,Oracle等关系型数据库直接将内容保存到硬盘中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写效率)。但是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的数据将会全部丢失。

为了解决这个缺点,Redis提供了将内存数据持久化到硬盘,以及用持久化文件来恢复数据库数据的功能。Redis 支持两种形式的持久化,一种是RDB快照(snapshotting),另外一种是AOF(append-only-file)。

1.1 RDB持久化

RDB是Redis用来进行持久化的一种方式,是把当前内存中的数据集快照写入磁盘,也就是 Snapshot 快照(数据库中所有键值对数据)。恢复时是将快照文件直接读到内存里。

RDB 有两种触发方式,分别是自动触发和手动触发。

1.1.1 手动持久化

在客户端操作时,只要执行了save命令,那么就会拍一次快照,将此次的数据全部存储到指定的文件中

127.0.0.1:6379> save
OK
  • 相关配置(配置文件中配置)
  • dbfilename:设置本地数据库文件名,默认值为 dump.rdb
  • dir:设置存储.rdb文件的路径
  • rdbcompression:设置存储至本地数据库时是否压缩数据,默认为 yes,采用 LZF 压缩,通常默认为开启状态,如果设置为no,可以节省 CPU 运行时间,但会使存储的文件变大(巨大)
  • rdbchecksum:默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但这样做会消耗大约10%的性能,如果希望获取到最大的性能提升,可以关闭此功能。
bind 127.0.0.1
port 6379
logfile "6379.log"
dir /root/redis-4.0.11/data
dbfilename drum-6379.rdb
rdbcompression yes
rdbchecksum yes
daemonize yes # 后台启动

1.1.2 save方法工作原理

使用save命令:此命令会使用Redis的主线程进程同步存储,阻塞当前的Redis服务器,造成服务不可用,直到RDB过程完成。无论当前服务器数据量大小,线上不要用。

Redis持久化底层原理详解_redis

1.1.3 bgsave

使用bgsave命令:此命令会通过fork()创建子进程,在后台进程存储。只有fork阶段会阻塞当前Redis服务器,不必到整个RDB过程结束,一般时间很短。因此Redis内部涉及到RDB都采用bgsave命令。

127.0.0.1:6379> bgsave

Redis持久化底层原理详解_数据持久化_02

1.1.2 自动持久化

一般我们是不会直接用命令生成RDB文件的,Redis支持自动触发RDB持久化机制,配置都在redis.conf文件里面。

save 900 1    # 900秒之内有1个key发生变化就保存一次
save 300 10 # 300秒之内有10个key发生变化就保存一次
save 60 10000 # 60秒之内有10000个key发生变化就保存一次

自动持久化底层采用的是bgsave指令。

  • 小结:

方式

save指令

bgsave指令

读写

同步

异步

阻塞客户端指令



额外消耗内存



启动新进程



1.2.3 特殊情况下保存数据

  • 服务器运行过程中重启
debug reload
  • 关闭服务器时指定保存数据
shutdown save

1.2.4 RDB总结

  • 优点
  • RDB是一个紧凑压缩的二进制文件,存储效率较高
  • RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
  • RDB恢复数据的速度要比AOF快很多
  • 应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。
  • 缺点
  • RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据,在这里有人说,把RDB持久化的频率调高一点不久可以吗?(​​save 1 1​​)你想想看,每次改变一个key,就进行一次全量快照的拍摄,这个性能是非常低的。
  • bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能
  • Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象

1.2 AOF持久化

AOF(append only file)持久化:AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态,也就是每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。

AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式

1.2.1 AOF持久化的三种策略

redis的AOF功能默认是关闭的,需要我们手动开启:

bind 127.0.0.1
port 6379
logfile "6379.log"
dir /root/redis-4.0.11/data
dbfilename drum-6379.rdb
rdbcompression yes
rdbchecksum yes
# save 10 2
daemonize yes
appendonly yes
appendfsync no
appendfilename appendonly-6379.aof
  • appendonly
  • yes:开启aof功能
  • no:关闭aof功能(默认值)
  • appendfsync
  • always(每次):每次写入操作均同步到AOF文件中,高并发下性能较低。
  • everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,默认配置
  • no(系统控制):由操作系统控制每次同步到AOF文件的周期,一般为30s每次。
  • appendfilename:aof文件名称
  • dir:aof文件路径

注意:AOF只会保存服务器所执行的写(set,del,add 等)的命令,对于其他对结果集并没有造成影响的命令是不会写入aof文件的。

1.2.2 AOF重写

AOF 持久化是通过保存被执行的写命令来记录数据库状态的,所以AOF文件的大小随着时间的流逝一定会越来越大,其中就包含了很多不必要的命令,如set某个key两次,其结果肯定为最后一次,那么前面一次的命令就没有必要再记录下来。

为了解决此问题,Redis引入了AOF重写机制用于压缩aof文件大小。

1.2.2.1 AOF重写原理

AOF重写实质上是将当前进程中的数据直接转换为对应的命令保存到aof文件中,这样就不会造成命令资源的浪费但是这个函数会进行大量的写入操作,所以调用这个函数的线程将被长时间的阻塞,因为Redis服务器使用单线程来处理命令请求,那么重写AOF期间,服务器将无法处理客户端发送来的命令请求;因此redis底层采用子进程的方式来将数据同步到aof文件当中。

  • 子进程在进行AOF重写期间,服务器进程还要继续处理命令请求,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的AOF文件中的数据不一致。

解决方案:

  • 当子进程正在同步时,主进程接收到的所有命令将会暂时存放在缓冲区中,来保证子进程在工作时,主进程接收到的指令不能被保存到aof文件。

Redis持久化底层原理详解_redis_03

重写条件:

  • 进程内已超时的数据不再写入文件
  • 忽略无效指令,重写时使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令,如:
set age 20
set age 30
set age 40

最终合并为:
set age 40
  • 对同一数据的多条写命令合并为一条命令,如:
rpush list a
rpush list b
rpush list c
rpush list d

最终合并为:
rpush list a b c d

AOF重写分为两种,一种为自动重写,另一种为手动重写。

1)手动重写

bgrewriteaof

执行完该命令后,会发现.aof文件变小了(前提是具备重写条件)。

2)自动重写

条件参数:

  • auto-aof-rewrite-min-size:aof_current_size每次要大于此参数的倍数将会触发重写操作
  • auto-aof-rewrite-percentage:重写百分比参数(默认百分之百)

在redis内部会自动维护以下几个参数:

  • aof_current_size:当前aof文件大小
  • aof_base_size:上一次执行完重写操纵时的aof文件大小

自动重写触发条件:

1、aof_current_size大于auto-aof-rewrite-min-size时将会触发重写,此后每次大于auto-aof-rewrite-min-size整倍数时就会触发一次重写操作。

2、(aof_current_size-aof_base_size)/aof_base_size大于等于auto-aof-rewrite-percentage时将会触发重写。

执行​​info Persistence​​命令,查看当前参数

127.0.0.1:6379> info Persistence
# Persistence
loading:0
rdb_changes_since_last_save:11
rdb_bgsave_in_progress:0
rdb_last_save_time:1585142012
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:1
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:0
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:6385664
aof_current_size:138
aof_base_size:138
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0
  • 配置自动重写redis.conf配置如下:
bind 127.0.0.1
port 6379
logfile "6379.log"
dir /root/redis-4.0.11/data
dbfilename drum-6379.rdb
rdbcompression yes
rdbchecksum yes
# save 10 2
daemonize yes
appendonly yes
appendfsync everysec
appendfilename appendonly-6379.aof
auto-aof-rewrite-min-size 0.5

1.3 总结

  • RDB
  • 优点
  • RDB是基于数据快照的理念设计的,每一个rdb文件都是一个已经压缩过的二进制文件,存储效率较高
  • 由于RDB是将数据全部存储在rdb文件中,即每个rdb文件都是原始数据,在恢复大数据集时的速度比 AOF 的恢复速度要快
  • 缺点:
  • 如果对数据恢复非常敏感,那么RDB的持久化效率将没有AOF的高,虽然RDB可以设置保存点save,但是因为RDB每次拍摄数据快照需要将此次数据快照的所有数据都写入rdb文件,虽然会fork出一个子进程帮我们工作,不会影响主进程的工作,但这并不是一个轻松的操作。会影响主进程的性能。
  • RDB持久化方式并没有缓冲区的概念,如果rdb的子进程正在将数据写入到rdb文件,会导致数据库的数据和rdb文件中保存的数据不一致。
  • AOF
  • 优点
  • AOF是基于日志形式的理念设计的,AOF将每一个操作指令的步骤都记录下来,因此同步的频率相对RDB来说可以非常的频繁。因此如果对数据比较敏感,不能够承受小规模的数据丢失,那么使用AOF是不错的选择。
  • AOF具有重写机制,可以有效的整理不必要的指令来压缩aof文件的大小,提升数据恢复的性能。
  • AOF 文件有序地保存了对数据库执行的所有写入操作,这些写入命令被redis保存到了aof文件上,这些指令让人可以轻松阅读,并且文件易于解析,当你中途不小心执行了​​flushall​​​指令,只要aof文件没有被重写,此时可以编辑aof文件删除​​flushall​​指令,来恢复数据
  • 缺点
  • 对于同等的数据量,AOF 文件的体积通常要大于 RDB 文件的体积。
  • 由于aof文件保存的是操作的命令,因此恢复起来速度要比RDB慢


标签:AOF,aof,Redis,详解,文件,RDB,重写,底层
From: https://blog.51cto.com/u_15919174/5959174

相关文章

  • Cookie 携带路径详解
    Cookie携带路径详解使用​​cookie.setPath()​​可以设置cookie的携带路径,如果不设置默认也会有一个携带路径,默认为当前路径的上一级路径啥意思?咱们来探究一下吧!先上个Dem......
  • 索引数据结构底层(全)
    读者忠告由于本文内容篇幅较长,涵盖了大家学习上、工作上的绝大多数索引,建议大家每一小节都认真阅读并理解透彻,如有疑问可在评论区留言探讨;文章目录​​读者忠告​​​​一、......
  • 数据存储全方案,详解持久化技术
    Android系统主要提供了三种方式用于简单的实现数据持久化功能,即文件存储,ShareedPreference存储以及数据库存储.当然,除了这三种方式之外,你还可以将数据保存在手机的SD卡......
  • 什么是Redis持久化,如何理解?
    其实redis就是一种高级的以键值对形式存储数据的数据库,而它的好处就是他可以支持数据的持久化,其实redis之所以会有这样的优点,主要是因为,redis的数据都是存放在内存中的,如......
  • redis—安装以及可视化
    redis是一种非关系型数据库,什么是非关系型数据库,之前我们在mysql专栏也有提到过,这边就不再过多的赘述,忘记了的小伙伴可以再次阅读这篇文章  终于明白了数据库的【关系......
  • Docker高级篇:实战Redis集群!从3主3从变为4主4从
    通过前面两篇,我们学会了三主三从的Redis集群搭建及主从容错切换迁移,随着业务增加,可能会有主从扩容的,所以,本文我们来实战主从扩容PS本系列:《Docker学习系列》教程已经发布......
  • 打开MCMC(马尔科夫蒙特卡洛)的黑盒子 - Pymc贝叶斯推理底层实现原理初探
    打开MCMC(马尔科夫蒙特卡洛)的黑盒子-Pymc贝叶斯推理底层实现原理初探我们在这篇文章里有尝试讨论三个重点。第一,讨论的MCMC。第二,学习MCMC的实......
  • RecyclerView详解
    1:和Listview的不同:1)Listview只支持纵向列表,RecyclerVeiw支持纵向、横向、网格以及瀑布流;2)ListView是2级缓存机制,RecyclerView是4级缓存机制3)ListView没有强制实现ViewHo......
  • 大端和小端模式详解
    前言对于不了解的看到或者听到“大端”、“小端”就如我一样可能就会很懵,不知道是啥?网上很多文章看的是眼花缭乱,云里雾里,所以本人决定自己写一篇让和我一样经历困惑的人,能......
  • 高性能Mysql主从架构的复制原理及配置详解(转)
    温习《高性能​​MySQL​​》的复制篇.1复制概述     Mysql内建的复制功能是构建大型,高性能应用程序的基础。将Mysql的数据分布到多个系统上去,这种分布的机制,是通过......