zoukankan      html  css  js  c++  java
  • 第八章 Redis数据持久化之AOF

    一、AOF概述

    AOF(Append-Only File)记录Redis中每次的写命令,类似mysql中的binlog,服务重启时会重新执行AOF中的命令将数据恢复到内存中,RDB(按策略持久化)持久化方式记录的粒度不如AOF(记录每条写命令),因此很多生产环境都是开启AOF持久化。AOF中记录了操作和数据,在日志文件中追加完成后才会将内存中的数据进行变更。
    
    AOF(append only file)只追加文件,记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。
    

    二、AOF持久化流程

    #1.客户端的请求写命令会被append追加到AOF缓冲区内;
    
    #2.AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
    
    #3.AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
    
    #4.Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
    

    三、 AOF配置

    开启了AOF之后,RDB就默认不使用了。使用下面的配置开启AOF以及策略。(如果使用AOF,推荐选择always方式持久化,否则在高并发场景下,每秒钟会有几万甚至百万条请求,如果使用everysec的方式的话,万一服务器挂了那几万条数据就丢失了)。
    
    #开启AOF持久化
    appendonly yes
    
    #AOF文件名
    appendfilename "appendonly.aof"
    
    #AOF文件存储路径 与RDB是同一个参数
    dir "/opt/app/redis6/data"
    
    #AOF策略,一般都是选择第一种[always:每个命令都记录],[everysec:每秒记录一次],[no:看机器的心情高兴了就记录]
    appendfsync always
    # appendfsync everysec
    # appendfsync no
    
    #aof文件大小比起上次重写时的大小,增长100%(配置可以大于100%)时,触发重写。[假如上次重写后大小为10MB,当AOF文件达到20MB时也会再次触发重写,以此类推]
    auto-aof-rewrite-percentage 100 
    
    #aof文件大小超过64MB时,触发重写
    auto-aof-rewrite-min-size 64mb 
    
    #是否在后台写时同步单写,默认值no(表示需要同步).这里的后台写,表示后台正在重写文件(包括bgsave和bgrewriteaof.bgrewriteaof网上很多资料都没有涉及到。其实关掉bgsave之后,主要的即是aof重写文件了).no表示新的主进程的set操作会被阻塞掉,而yes表示新的主进程的set不会被阻塞,待整个后台写完成之后再将这部分set操作同步到aof文件中。但这可能会存在数据丢失的风险(机率很小),如果对性能有要求,可以设置为yes,仅在后台写时会异步处理命令.
    no-appendfsync-on-rewrite no
    
    # 指redis在恢复时,会忽略最后一条可能存在问题的指令。默认值yes。即在aof写入时,可能存在指令写错的问题(突然断电,写了一半),这种情况下,yes会log并继续,而no会直接恢复失败.
    aof-load-truncated yes
    

    四、AOF持久化策略

    AOF分别有三种备份策略,分别是[always:每个命令都记录],[everysec:每秒记录一次],[no:看机器的心情高兴了就记录],针对这三种策略给出如下说明。
    

    1.策略说明

    策略 说明 优点
    always 每次执行,都会持久化到AOF文件中 不丢失数据
    everysec 每秒持久化一次 减少IO
    no 根据服务器性能持久化 全自动

    2.策略抉择

    命令 Always Everysec no
    优点 不丢失数据 每秒一次fsync,减少IO 不用管,全自动
    缺点 IO开销大 丢1秒钟的数据 不可控

    五、AOF模式的优点

    1.使用AOF Redis会更具有可持久性(durable):你可以有很多不同的fsync策略:没有fsync,每秒fsync,每次请求时fsync。使用默认的每秒fsync策略,写性能也仍然很不错(fsync是由后台线程完成的,主线程继续努力地执行写请求),即便你也就仅仅只损失一秒钟的写数据。
    
    2.AOF日志是一个追加文件,所以不需要定位,在断电时也没有损坏问题。即使由于某种原因文件末尾是一个写到一半的命令(磁盘满或者其他原因),redis-check-aof工具也可以很轻易的修复。
    
    3.当AOF文件变得很大时,Redis会自动在后台进行重写。重写是绝对安全的,因为Redis继续往旧的文件中追加,使用创建当前数据集所需的最小操作集合来创建一个全新的文件,一旦第二个文件创建完毕,Redis就会切换这两个文件,并开始往新文件追加。
    
    4.AOF文件里面包含一个接一个的操作,以易于理解和解析的格式存储。你也可以轻易的导出一个AOF文件。例如,即使你不小心错误地使用FLUSHALL命令清空一切,如果此时并没有执行重写,你仍然可以保存你的数据集,你只要停止服务器,删除最后一条命令,然后重启Redis就可以。
    
    总结:
    1)备份机制更稳健,丢失数据概率更低。
    2)可读的日志文本,通过操作AOF稳健,可以处理误操作。
    

    六、AOF重写机制

    1.AOF重写机制概述

    1.因为 AOF 的运作方式是不断地将命令追加到文件的末尾,所以随着写入命令的不断增加, AOF 文件的体积也变得越来越大。举个例子,如果你对一个计数器调用了 100 次 INCR ,那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录。然而在实际上,只使用一条 SET 命令已经足以保存计数器的当前值了,其余 99 条记录实际上都是多余的。
    
    2.为了处理这种情况, Redis 支持一种有趣的特性:可以在不断服务客户端的情况下,对 AOF 文件进行重建。执行 BGREWRITEAOF 命令, Redis 将生产一个新的 AOF 文件,这个文件包含重建当前数据集所需的最少命令。
    

    2. AOF重写配置

    配置名 含义
    appendonly 开启AOF持久化功能
    auto-aof-rewrite-min-size 触发重写的最小尺寸
    auto-aof-rewrite-percentage AOF文件增长率
    aof_current_size AOF当前尺寸
    aof_base_size AOF上次启动和重写的尺寸(单位:字节)

    3. AOF重写触发机制

    根据配置,AOF持久化触发机制如下:
    
    1.aof_current_size > auto-aof-rewrite-min-size
    2.(aof_current_size - aof_base_size) / aof_base_size > auto-aof-rewrite-percentage
    

    4. AOF重写流程

    1.bgrewriteaof触发重写,判断是否当前有bgsave或bgrewriteaof在运行,如果有,则等待该命令结束后再继续执行。
    
    2.主进程fork出子进程执行重写操作,保证主进程不会阻塞。
    
    3.子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入aof_buf缓冲区和aof_rewrite_buf重写缓冲区保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。
    
    4.子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。2).主进程把aof_rewrite_buf中的数据写入到新的AOF文件。
    
    5.使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。
    

    七、AOF持久化缺点

    1.对同样的数据集,AOF文件通常要大于等价的RDB文件。
    
    2.AOF可能比RDB慢,这取决于准确的fsync策略。通常fsync设置为每秒一次的话性能仍然很高,如果关闭fsync,即使在很高的负载下也和RDB一样的快。不过,即使在很大的写负载情况下,RDB还是能提供能好的最大延迟保证。
    
    3.在过去,我们经历了一些针对特殊命令(例如,像BRPOPLPUSH这样的阻塞命令)的罕见bug,导致在数据加载时无法恢复到保存时的样子。这些bug很罕见,我们也在测试套件中进行了测试,自动随机创造复杂的数据集,然后加载它们以检查一切是否正常,但是,这类bug几乎不可能出现在RDB持久化中。为了说得更清楚一点:Redis AOF是通过递增地更新一个已经存在的状态,像MySQL或者MongoDB一样,而RDB快照是一次又一次地从头开始创造一切,概念上更健壮。
    但是,
    1)要注意Redis每次重写AOF时都是以当前数据集中的真实数据从头开始,相对于一直追加的AOF文件(或者一次重写读取老的AOF文件而不是读内存中的数据)对bug的免疫力更强。
    2)我们还没有收到一份用户在真实世界中检测到崩溃的报告。
    
    总结:
    1)比起RDB占用更多的磁盘空间。
    2)恢复备份速度要慢。
    3)每次读写都同步的话,有一定的性能压力。
    4)存在个别Bug,造成恢复不能。 
    

    八、AOF持久化优缺点总结

    优点:可以最大程度保证数据不丢失
    缺点:日志记录量级比较大
    

    九、RDB与AOF抉择

    1.RDB与AOF比较

    命令 RDB AOF
    启动优先级
    体积
    恢复速度
    数据安全性 丢数据 根据策略的不同,丢数据的情况也不同
    轻重

    2.官网建议

    1.RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
    2.AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾. 
    3.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
    4.只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
    5.同时开启两种持久化方式
    6.在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据, 因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
    7.RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢? 
    建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份), 快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。
    8.性能建议
    因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。
    如果使用AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。
    代价,一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。
    只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。
    默认超过原大小100%大小时重写可以改到适当的数值。
    

    3. RDB与AOF之间的优劣势

    #1.RDB的优点
    1.压缩后的二进制文件,适用于备份、全量复制及灾难恢复。
    2.RDB恢复数据性能优于AOF方式。
    
    #2.RDB的缺点
    1.无法做到实时持久化,每次都要创建子进程,频繁操作成本过高
    2.保存后的二进制文件,不同版本直接存在兼容性问题
    
    #3.AOF的优点
    1.以文本形式保存,易读
    2.记录写操作保证数据不丢失
    
    #4.AOF的缺点
    1.存储所有写操作命令,且文件为文本格式保存,未经压缩,文件体积高。
    2.恢复数据时重放AOF中所有代码,恢复性能弱于RDB方式。
    

    十、 AOF与RDB混合

    看了上面的RDB和AOF的介绍后,我们可以发现,使用RDB持久化会有数据丢失的风险,但是恢复速度快,而使用AOF持久化可以保证数据完整性,但恢复数据的时候会很慢。于是从Redis4之后新增了混合AOF和RDB的模式,先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB何AOF两部分恢复数据,即保证了数据完整性,又提高了恢复的性能。
    	
    开启混合模式后,每当bgrewriteaof命令之后会在AOF文件中以RDB格式写入当前最新的数据,之后的新的写操作继续以AOF的追加形式追加写命令。当redis重启的时候,加载 aof 文件进行恢复数据:先加载 rdb 的部分再加载剩余的 aof部分。
    

    1.混合配置

    修改下面的参数即可开启AOF,RDB混合持久化
    aof-use-rdb-preamble yes
    

    2.混合模式示例

    开启混合持久化模式后,重写之后的aof文件里和rdb一样存储二进制的快照数据,继续往redis中进行写操作,后续操作在aof中仍然是以命令的方式追加。因此重写后aof文件由两部分组成,一部分是类似rdb的二进制快照,另一部分是追加的命令文本。
    
    # step1: 进入Redis, 写入数据
    [root@alvin-test-os redis]# redis-cli --raw
    127.0.0.1:6379> set name alvin
    OK
    127.0.0.1:6379> set age 18
    OK
    127.0.0.1:6379> set add 上海
    OK
    127.0.0.1:6379> exit
    
    # Step 2: 查看备份文件
    [root@alvin-test-os redis]# ll data/
    总用量 8
    -rw-r--r--. 1 root root 121 11月 24 15:39 appendonly.aof
    -rw-r--r--. 1 root root 116 11月 24 15:39 dump.rdb
    
    [root@alvin-test-os redis]# cat data/appendonly.aof | grep add
    add
    [root@alvin-test-os redis]# cat data/appendonly.aof
    *2
    $6
    SELECT
    $1
    0
    *3
    $3
    set
    $4
    name
    $5
    alvin
    *3
    $3
    set
    $3
    age
    $2
    18
    *3
    $3
    set
    $3
    add
    $6
    上海
    
    # Step 3: 启动备份
    [root@alvin-test-os redis]# redis-cli --raw
    127.0.0.1:6379> BGREWRITEAOF
    Background append only file rewriting started
    127.0.0.1:6379> exit
    
    # Step 4: 查看配置文件发现AOF备份文件变成了二进制文件
    [root@alvin-test-os redis]# cat data/appendonly.aof
    REDIS0009�  redis-ver6.0.9�
    �edis-bits�@�ctime��_used-mem��4
     aof-preamble���namealvinadd上海age���6����&
    [root@alvin-test-os redis]#
    
    # Step 5: 再次写入文件
    [root@alvin-test-os redis]# redis-cli --raw
    127.0.0.1:6379> set company 上海
    OK
    127.0.0.1:6379> exit
    
    # Step 6:再次查看备份文件发现被分成了两份,一份二进制,一份AOF备份
    [root@alvin-test-os redis]# cat data/appendonly.aof
    REDIS0009�  redis-ver6.0.9�
    �edis-bits�@�ctime��_used-mem��4
     aof-preamble���namealvinadd上海age���6����&*2
    $6
    SELECT
    $1
    0
    *3
    $3
    set
    $7
    company
    $15
    上海
    

    3.备份Redis数据

    1.Redis 对于数据备份是非常友好的,因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建,就不会进行任何修改。
    2.当服务器要创建一个新的 RDB 文件时,它先将文件的内容保存在一个临时文件里面,当临时文件写入完毕时,程序才使用临时文件替换原来的 RDB 文件。
    3.这也就是说,无论何时, 复制 RDB 文件都是绝对安全的。
    
    #以下是我们的建议:
    1.创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。
    2.确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。
    3.至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。
    

    4.RDB持久化高级配置

    #编辑配置文件
    [root@db01 redis]# vim /etc/redis/6379/redis.conf
    #后台备份进程出错时,主进程停不停止写入? 主进程不停止容易造成数据不一致
    stop-writes-on-bgsave-error yes
    #导出的rdb文件是否压缩 如果rdb的大小很大的话建议这么做
    rdbcompression yes
    #导入rbd恢复时数据时,要不要检验rdb的完整性 验证版本是不是一致
    rdbchecksum yes
    

    5.AOF持久化高级配置

    #编辑配置文件
    [root@db01 redis]# vim /etc/redis/6379/redis.conf
    #正在导出rdb快照的过程中,要不要停止同步aof
    no-appendfsync-on-rewrite yes
    #aof文件大小比起上次重写时的大小,增长率100%时重写,缺点:业务开始的时候,会重复重写多次
    auto-aof-rewrite-percentage 100
    #aof文件,至少超过64M时,重写
    auto-aof-rewrite-min-size 64mb
    
  • 相关阅读:
    SpringCloud简介及使用
    容器云技术选择之kubernetes和swarm对比
    LXC简单介绍与使用
    go recover让崩溃的程序继续执行
    dbeaver可视化工具-连接clickhouse
    JavaScript异步与Promise基本用法(resolve与reject)
    通过mysql操作clickhouse
    clickhouse客户端使用
    clickhouse安装数据导入及查询测试
    spring boot druid数据源
  • 原文地址:https://www.cnblogs.com/jhno1/p/15634316.html
Copyright © 2011-2022 走看看