配置文件在哪里?怎么配置?

  • 配置文件名 redis.conf

  • 路径在/etc/redis/redis.conf

以下是来自官方配置文件模板的RDB配置内容 https://download.redis.io/redis-stable/redis.conf

############################## APPEND ONLY MODE ###############################

# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
#
# The Append Only File is an alternative persistence mode that provides
# much better durability. For instance using the default data fsync policy
# (see later in the config file) Redis can lose just one second of writes in a
# dramatic event like a server power outage, or a single write if something
# wrong with the Redis process itself happens, but the operating system is
# still running correctly.
#
# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Note that changing this value in a config file of an existing database and
# restarting the server can lead to data loss. A conversion needs to be done
# by setting it via CONFIG command on a live server first.
#
# Please check https://redis.io/topics/persistence for more information.

appendonly no

# The base name of the append only file.
#
# Redis 7 and newer use a set of append-only files to persist the dataset
# and changes applied to it. There are two basic types of files in use:
#
# - Base files, which are a snapshot representing the complete state of the
#   dataset at the time the file was created. Base files can be either in
#   the form of RDB (binary serialized) or AOF (textual commands).
# - Incremental files, which contain additional commands that were applied
#   to the dataset following the previous file.
#
# In addition, manifest files are used to track the files and the order in
# which they were created and should be applied.
#
# Append-only file names are created by Redis following a specific pattern.
# The file name's prefix is based on the 'appendfilename' configuration
# parameter, followed by additional information about the sequence and type.
#
# For example, if appendfilename is set to appendonly.aof, the following file
# names could be derived:
#
# - appendonly.aof.1.base.rdb as a base file.
# - appendonly.aof.1.incr.aof, appendonly.aof.2.incr.aof as incremental files.
# - appendonly.aof.manifest as a manifest file.

appendfilename "appendonly.aof"

# For convenience, Redis stores all persistent append-only files in a dedicated
# directory. The name of the directory is determined by the appenddirname
# configuration parameter.

appenddirname "appendonlydir"

# The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log. Slow, Safest.
# everysec: fsync only one time every second. Compromise.
#
# The default is "everysec", as that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".

# appendfsync always
appendfsync everysec
# appendfsync no

# When the AOF fsync policy is set to always or everysec, and a background
# saving process (a background save or AOF log background rewriting) is
# performing a lot of I/O against the disk, in some Linux configurations
# Redis may block too long on the fsync() call. Note that there is no fix for
# this currently, as even performing fsync in a different thread will block
# our synchronous write(2) call.
#
# In order to mitigate this problem it's possible to use the following option
# that will prevent fsync() from being called in the main process while a
# BGSAVE or BGREWRITEAOF is in progress.
#
# This means that while another child is saving, the durability of Redis is
# the same as "appendfsync no". In practical terms, this means that it is
# possible to lose up to 30 seconds of log in the worst scenario (with the
# default Linux settings).
#
# If you have latency problems turn this to "yes". Otherwise leave it as
# "no" that is the safest pick from the point of view of durability.

no-appendfsync-on-rewrite no

# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (if no rewrite has happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a percentage of zero in order to disable the automatic AOF
# rewrite feature.

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# An AOF file may be found to be truncated at the end during the Redis
# startup process, when the AOF data gets loaded back into memory.
# This may happen when the system where Redis is running
# crashes, especially when an ext4 filesystem is mounted without the
# data=ordered option (however this can't happen when Redis itself
# crashes or aborts but the operating system still works correctly).
#
# Redis can either exit with an error when this happens, or load as much
# data as possible (the default now) and start if the AOF file is found
# to be truncated at the end. The following option controls this behavior.
#
# If aof-load-truncated is set to yes, a truncated AOF file is loaded and
# the Redis server starts emitting a log to inform the user of the event.
# Otherwise if the option is set to no, the server aborts with an error
# and refuses to start. When the option is set to no, the user requires
# to fix the AOF file using the "redis-check-aof" utility before to restart
# the server.
#
# Note that if the AOF file will be found to be corrupted in the middle
# the server will still exit with an error. This option only applies when
# Redis will try to read more data from the AOF file but not enough bytes
# will be found.

什么时候触发AOF?

这个取决于配置文件redis.conf 配置项

appendonly no/yes

# The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log. Slow, Safest.
# everysec: fsync only one time every second. Compromise.

appendfsync always
appendfsync everysec
appendfsync no
  • appendonly

    • yes 开启

    • no 不开

  • appendfsync

    • always: 执行一句写一句

    • everysec: 每秒一次调用 syscall write(...) 将 sds aof_buffer 写入到内核缓冲区,并调用fsync() 刷盘

    • no: 不主动写aof文件 只调syscall write(...) 将 sds aof_buffer 写入到内核缓冲区,由操作系统定期刷盘(linux 大概30s 刷一次,具体得看配置项)

综上,触发时机如下:

  1. 主eventloop中上次事件处刚处理完,空闲等待下次事件来的时候,调用的beforesleep(...) 里机会调用 redis封装的flushAppendedOnlyFile(...) 函数。 -- 总的来说就是主事件循环空闲间隙就会调用

  2. redis 周期函数servercron到期调用

  3. redis 关闭服务

  4. 使用命令关闭AOF

AOF 写入细节

redis 用sds 定义了一个 aof_buf 独享,用于作redis 用户写入缓冲区

sds aof_buf; /* AOF buffer, written before entering the event loop */

AOF写入源码

// file: aof.c
/* Perform the fsync if needed. 如果需要的话,执行fsync操作 */
// 检查`server.aof_fsync`的值是否为`AOF_FSYNC_ALWAYS`,表示每次写入AOF文件后都需要执行fsync操作。
if (server.aof_fsync == AOF_FSYNC_ALWAYS) {
    /* redis_fsync is defined as fdatasync() for Linux in order to avoid
     * flushing metadata. */
    // 在Linux系统中,`redis_fsync`被定义为`fdatasync()`,这样做是为了避免同时将文件的元数据(如修改时间)也写入磁盘。
    // 监控fsync操作的延迟
    latencyStartMonitor(latency);
    redis_fsync(server.aof_fd); /* Let's try to get this data on the disk fsync操作,将AOF文件的数据写入磁盘。 */
    // 结束监控fsync操作的延迟。
    latencyEndMonitor(latency);
    // 检查aof-fsync-always 字段配置,如果开启的话,将fsync操作的延迟添加到监控样本中。
    latencyAddSampleIfNeeded("aof-fsync-always",latency);
    // 更新最后一次fsync时间戳
    server.aof_last_fsync = server.unixtime;
}
// appendfsync 字段配置是否为 everysec 对应宏:`AOF_FSYNC_EVERYSEC`,
// 是否超时上次fsync操作的时间 
else if ((server.aof_fsync == AOF_FSYNC_EVERYSEC &&
            server.unixtime > server.aof_last_fsync)) {
    // 如果没有正在进行的同步操作,那么在后台执行fsync操作。
    if (!sync_in_progress) aof_background_fsync(server.aof_fd); // aof_background_fsync(server.aof_fd); 使用后再线程刷盘
    server.aof_last_fsync = server.unixtime;
}

AOF 写入步骤

  1. 将写入内容,追加到sds aof_buf

  2. 定时调用 syscall 将aof_buf 中的内容写入到内核缓冲区(page cache), redis 里会调用flushAppenedOnlyFile()这个函数,这个函数里会调用syscall write(...); flushAppendedOnlyFile(...)的驱动事件有四种:

    1. 主eventloop中上次事件处刚处理完,空闲等待下次事件来的时候,调用的beforesleep(...) 里机会调用 redis封装的flushAppendedOnlyFile(...) 函数。 -- 总的来说就是主事件循环空闲间隙就会调用

    2. redis 周期函数servercron到期调用

    3. redis 关闭服务

    4. 使用命令关闭AOF

  3. 将系统内核缓冲区中的数据写入磁盘(刷盘) -- 看上面源码,这里的刷盘也是在flushAppendOlnyFile(...) 函数中。

flushAppendOnlyFile(...) 源码

// file: aof.c

/* Flushes the append only file buffer on disk. */
void flushAppendOnlyFile(void) {
    /* Write the append only file buffer on disk. */
    if (server.aof_buf && sdslen(server.aof_buf) > 0) {
        /* Perform the write operation. */
        if (write(server.aof_fd, server.aof_buf, sdslen(server.aof_buf)) == -1) {
            serverLog(LL_WARNING, "Unable to write to the append only file: %s", strerror(errno));
            exit(1);
        }
        /* Update the AOF current size. */
        server.aof_current_size += sdslen(server.aof_buf);
        /* Reset the AOF buffer. */
        sdsfree(server.aof_buf);
        server.aof_buf = sdsempty();
    }

    /* Sync data on disk. */
    if (server.aof_fsync == AOF_FSYNC_ALWAYS) {
        /* Perform the fsync if needed. */
        if (fsync(server.aof_fd) == -1) {
            serverLog(LL_WARNING, "Unable to fsync the append only file: %s", strerror(errno));
            exit(1);
        }
    } else if (server.aof_fsync == AOF_FSYNC_EVERYSEC) {
        /* Check if a second has passed since the last fsync. */
        if ((server.unixtime % 1) == 0 && server.aof_last_fsync_offset != server.aof_current_size) {
            /* Perform the fsync. */
            if (fsync(server.aof_fd) == -1) {
                serverLog(LL_WARNING, "Unable to fsync the append only file: %s", strerror(errno));
                exit(1);
            }
            /* Update the AOF last fsync. */
            server.aof_last_fsync = server.unixtime;
            server.aof_last_fsync_offset = server.aof_current_size;
        }
    }
}

// 这段代码展示了 `flushAppendOnlyFile` 函数的基本工作流程:
/*******************************************************
1. 检查 AOF 缓冲区(`server.aof_buf`)是否有数据需要写入。
2. 如果有数据,使用 `write` 系统调写入数据到 AOF 文件。
3. 更新 AOF 当前文件大小(`server.aof_current_size`)。
4. 重置 AOF 缓冲区。
5. 根据配置的 `fsync` 策略,执行 `fsync` 或 `fdatasync` 操作以确保数据被同步到磁盘上。
*******************************************************/

// 请注意,这个代码是一个简化版本,实际的 Redis 源码可能包含更多的错误处理和边缘情况处理。您可以在 Redis 的官方 GitHub 仓库中找到完整的源码。

AOF 什么时候刷盘?

AOF工作流程大致分为三部,命令追加到aof_buf -> 向系统发起写请求syscall 将aof_buf内容 写入到内核缓冲区 -> 根据配置文件刷盘/或者由系统刷盘. AOF 触发时机有四个:

  • 关闭服务 shutdown

  • 通过指令关闭AOF

  • 周期函数调用

  • 空闲事件检查函数beforesleep(...)

其中调用根据配置的appendfsync刷盘策略也有不同得刷盘频率,具体见上...

AOF 重写

AOF 重写主要依赖配置文件这三项配置项

# 自动触发:根据 auto-aof-rewrite-min-size和auto-aof-rewrite-percentage 参数确定自动触发时机。
 
# auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认为64M 
# auto-aof-rewrite-percentage:代表当前AOF文件空间(aof_current_size)和 上一次重写后AOF文件空间(aof_base_size)的比值。默认100%
# aof-rewrite-incremental-fsync:重写缓冲区定量刷盘(写入磁盘)数据量阈值,默认32M

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-rewrite-incremental-fsync 32mb

如何触发AOF重写

触发重写有两种方式:

  • 达到配置条件触发:

  • 手动命令bgrewriteaof

重写流程

  • 检查受否有子进程正在进行重写AOF,若有,返回下次重写,无,fork

  • 创建临时AOF文件,获取数据库中的数据,重写redis 命令,重写内容加入到重写用户缓冲区 aof_rewrite_buf 中 (这里如果有新的命令过来,会将新命令追加到aof_rewrite_buf中)

    • 重写期间如果有新命令:

1.将新命令加入到主进程中的aof_buf 并写入到旧AOF文件中

2.将新命令加入到重写进程中的aof_rewrite_buf 并写入新AOF文件中

  • 根据配置文件 字段 aof-rewrite-incremental-fsync 定量写入磁盘

  • 重写完成,替换旧AOF文件

再偷一张大佬的图