【Redis原理探索】深入对持久化原理的AOF(专题篇)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【Redis原理探索】深入对持久化原理的AOF(专题篇)

前提回顾


AOF的简介


  • Redis的AOF是类似的Log的机制,每次写操作都会写到硬盘上,当系统崩溃时,可以通过AOF来恢复数据。


  • 每个带有写操作的命令被Redis服务器端收到运行时,该命令都会被记录到AOF文件上。由于只是一个append到文件操作(采用的是存储aof_buf中,并且采用异步方法fsync/fdatasync),所以写到硬盘上的操作往往非常快


AOF的实现


Redis AOF机制包括了两件事,AOF和Rewrite。


  • AOF类似于普通数据库管理系统日志恢复点,当AOF文件随着写命令的运行膨胀时,当文件大小触碰到临界时,rewrite会被运行


  • Rewrite会像replication一样,fork出一个子进程,创建一个临时文件,遍历数据库,将每个key、value对输出到临时文件


  • 输出格式就是Redis的命令,但是为了减小文件大小,会将多个key、value对集合起来用一条命令表达


  • 在rewrite期间的写操作会保存在内存的aof_rewrite_buf_block中,rewrite成功后这些操作也会复制到临时文件中,在最后临时文件会代替AOF文件


以上在AOF打开的情况下,如果AOF是关闭的,那么rewrite操作可以通过bgrewriteaof命令来进行。



AOF的流程


image.png


  • Redis Server启动,如果AOF机制打开那么初始化AOF状态,并且如果存在AOF文件,读取AOF文件。随着Redis不断接受命令,每个写命令都被添加到AOF文件,AOF文件膨胀到重写阈值需要重写时又或者接收到客户端的bgrewriteaof命令。


  • fork出一个子进程进行rewrite,而父进程继续接受操作命令,现在的写操作命令都会被额外添加到一个aof_rewrite_buf_blocks缓冲中。


  • 信号,把aof_rewrite_buf_blocks的缓冲添加到rewrite后的AOF文件中,然后切换AOF的文件fd,采用新文件覆盖旧文件。rewrite任务完成,继续第二个步骤。




关键点


  • 由于写操作通常是有缓冲的,有可能AOF操作并没有写到硬盘中,可以通过fsync()/fdatasync()来强制输出到硬盘中


  • 而fsync()的频率可以通过配置文件中的flush策略来指定,可以选择每次事件循环写操作都强制fsync或者每秒fsync至少运行一次


  • **当rewrite子进程开始后,父进程接受到的命令会添加到aof_rewrite_buf_blocks中,使得rewrite成功后,将这些命令添加到新文件中。


  • 在rewrite过程中,原来的AOF也可以选择是否继续添加,由于存在性能上的问题,在rewrite过程中,如果fsync()继续执行,会导致IO性能受损影响Redis性能。所以一般情况下rewrite期间禁止fsync()到旧AOF文件这策略可以在配置文件中修改。(就是在rewrite过程中aof操作的同步机制,可以会暂时停止不会save到aof文件中)。


  • 在rewrite结束后,在将新rewrite文件重命名为配置中指定的文件时,如果旧AOF存在,那么会unlink旧文件并删除


  • 这是就存在一个问题,处理rewrite文件迁移的是主线程,rename(oldpath, newpath)过程会覆盖旧文件,这是rename会unlink(oldfd),而unlink操作会导致block主线程





自动的bgrewriteaof


  • 避免aof文件过大,我们会周期性的做bgrewriteaof来重整aof文件。以前我们会额外的配置crontab在业务低峰期执行这个命令,这额外的增加一个workaroud的脚本任务在大集群里是很糟糕的,不易检查,出错无法即时发现


  • 于是这个自动bgrewriteaof功能被直接加到redis的内部。首先对于aof文件,server对象添加一个字段来记录aof文件的大小server.appendonly_current_size每次aof发生变化都会维护这个字段


aof.c


nwritten = write(server.appendfd,server.aofbuf,sdslen(server.aofbuf));
.....
server.appendonly_current_size += nwritten;
复制代码


bgrewriteaof完毕或者实例启动载入aof数据后也会调用aofUpdateCurrentSize这个函数维护这个字段,同时会记录下此时的aof文件的大小server.auto_aofrewrite_base_size作为基准值,用于接下来判断aof增长率。



aof.c


aofUpdateCurrentSize();
server.auto_aofrewrite_base_size = server.appendonly_current_size;
复制代码


有了当前值和基准值我们就可以判断aof文件的增长情况。另外还需要配置两个参数来判断是否需要自动触发bgrewriteaof。


redis.h


int auto_aofrewrite_perc; /* Rewrite AOF if % growth is > M and... */
off_t auto_aofrewrite_min_size; /* the AOF file is at least N bytes. */
复制代码


  • auto_aofrewrite_perc: AOF文件的大小超过基准百分之多少后触发bgrewriteaof。默认这个值设置为100,意味着当前AOF是基准大小的两倍的时候触发bgrewriteaof把它设置为0可以禁用自动触发的功能


  • auto_aofrewrite_min_size: 当前AOF文件大于多少字节后才触发。避免在aof较小的时候无谓行为。默认大小为64mb。


两个参数都是可以在conf里静态配置,或者通过config set来动态修改的。


redis 127.0.0.1:6379> config get auto-aof-rewrite-percentage
1) "auto-aof-rewrite-percentage"
2) "100"
redis 127.0.0.1:6379> config get auto-aof-rewrite-min-size
1) "auto-aof-rewrite-min-size"
2) "1048576"
redis 127.0.0.1:6379> config get auto-aof-rewrite-min-size
1) "auto-aof-rewrite-min-size"
2) "1048576"
redis 127.0.0.1:6379> config set auto-aof-rewrite-percentage 200
OK
redis 127.0.0.1:6379> config set auto-aof-rewrite-min-size 10485760
OK
复制代码


然后就是触发检查的主逻辑,serverCron时间事件中每次都会检查现有状态和参数来判断是否需要启动bgrewriteaof


redis.c


if (server.bgsavechildpid == -1 &&
              server.bgrewritechildpid == -1 &&
              server.auto_aofrewrite_perc &&
              server.appendonly_current_size > server.auto_aofrewrite_min_size)
          {
             long long base = server.auto_aofrewrite_base_size ?
                             server.auto_aofrewrite_base_size : 1;
             long long growth = (server.appendonly_current_size*100/base) - 100;
             if (growth >= server.auto_aofrewrite_perc) {
                 redisLog(REDIS_NOTICE,"Starting automatic rewriting of AOF on %lld%% growth",growth);
                 rewriteAppendOnlyFileBackground();
             }
         }
复制代码


以上代码显示,如果aof文件增长百分率growth大于auto_aofrewrite_perc,则自动的触发后一个bgrewriteaof




延迟bgrewriteaof


这是个小的改进,手动触发的bgrewriteaof的时候如果同时存在bgsave在备份,会推迟这次操走的事件,设置server.aofrewrite_scheduled=1,待到bgsave结束后的下一次serverCron里才会触发


设置 aofrewrite_scheduled=1


aof.c

void bgrewriteaofCommand(redisClient *c) {
     if (server.bgrewritechildpid != -1) {
         addReplyError(c,"Background append only file rewriting already in 
         progress");
     } else if (server.bgsavechildpid != -1) {
         server.aofrewrite_scheduled = 1;
         addReplyStatus(c,"Background append only file rewriting 
         scheduled");
     } else if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
         addReplyStatus(c,"Background append only file rewriting 
         started");
     } else {
         addReply(c,shared.err);
     }
 }
复制代码



触发bgrewriteaof


redis.c

if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1 &&
        server.aofrewrite_scheduled){
         rewriteAppendOnlyFileBackground();
    }






相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
6天前
|
存储 缓存 NoSQL
Redis中的rdb和aof
本文深入探讨了Redis的持久化机制,包括RDB和AOF两种方式。详细解释了RDB的工作原理、优势和劣势,以及AOF的实现原理、配置选项、文件重写机制和三种数据同步方式,还介绍了AOF文件修复工具redis-check-aof的使用,并通过实例展示了如何开启和配置AOF持久化方式。
Redis中的rdb和aof
|
9天前
|
缓存 NoSQL Linux
redis的原理(三)
redis的原理(三)
redis的原理(三)
|
20天前
|
存储 NoSQL Redis
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
Redis持久化、RDB和AOF方案、Redis主从集群、哨兵、分片集群、散列插槽、自动手动故障转移
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
|
3天前
|
存储 缓存 NoSQL
Redis 大 Key 对持久化的影响及解决方案
Redis 大 Key 对持久化的影响及解决方案
11 1
|
9天前
|
存储 缓存 NoSQL
redis的原理(四)
redis的原理(四)
|
9天前
|
存储 缓存 NoSQL
redis的原理(二)
redis的原理(二)
|
9天前
|
缓存 NoSQL 安全
Redis的原理(一)
Redis的原理(一)
|
3天前
|
存储 NoSQL 安全
8)详解 Redis 的配置文件以及数据持久化
8)详解 Redis 的配置文件以及数据持久化
9 0
|
3天前
|
存储 缓存 NoSQL
深入探究Redis的AOF持久化:保障数据安全与恢复性能的关键机制
深入探究Redis的AOF持久化:保障数据安全与恢复性能的关键机制
13 0
|
2月前
|
运维 监控 NoSQL
【Redis】哨兵(Sentinel)原理与实战全解~炒鸡简单啊
Redis 的哨兵模式(Sentinel)是一种用于实现高可用性的机制。它通过监控主节点和从节点,并在主节点故障时自动进行切换,确保集群持续提供服务。哨兵模式包括主节点、从节点和哨兵实例,具备监控、通知、自动故障转移等功能,能显著提高系统的稳定性和可靠性。本文详细介绍了哨兵模式的组成、功能、工作机制以及其优势和局限性,并提供了单实例的安装和配置步骤,包括系统优化、安装、配置、启停管理和性能监控等。此外,还介绍了如何配置主从复制和哨兵,确保在故障时能够自动切换并恢复服务。
下一篇
无影云桌面