楔子 Redis 的配置非常多,加上注释的话,配置文件大概一两千行,里面有大量的配置可以供我们进行设置。其实关于 Redis 的配置我们之前也提到过,比如:开启多线程、设置线程数、数据结构内部存储元素的数量限制等等,那么下面我们就来介绍一下 Redis 配置文件中的一些其它的常见配置项。 配置文件 不过提到了配置文件,这里再提一个命令,叫做 config,是专门获取当前 Redis 配置项的。
config get requirepass查看密码,如果没有设置的话会返回空字符串。config get dir 查看 redis-server 的启动路径,我是在 /root 下启动的。 既然有 get,那就有 set。
所以修改配置有两种方式,一种是直接在命令行中通过 config set 进行修改,该方式修改之后会立即生效,但只会影响当前这一个客户端,其它客户端不受影响。并且客户端重连之后,所做的修改会消失。 第二种就是修改配置文件,该方式修改之后必须重启 Redis 服务端才可以生效,并且对所有客户端都永久生效。 下面来介绍配置文件,首先根据功能的不同,可以将 Redis 的配置文件分为以下几个部分,我们分别来介绍,当然 Redis 内部就是这么分的。 units
里面定义了一些基本单位,而且大小写不敏感。 includes
可以将配置写在其他地方,然后 include 进来,就跟 C 的头文件一样。 network
因此可以看到 network 是和网络连接相关的。 general
这部分对应的是一些通用的配置。 SECURITY
CLIENT
MEMORY MANAGEMENT
以上就是一些我们经常使用的配置,当然还有一部分与持久化有关的配置,我们在介绍持久化的时候单独说。 什么是 Redis 的持久化 Redis 的一大特点就是可以将数据持久化,说白了就是将内存中的数据写入到磁盘保证不丢失,并且还能将数据从磁盘加载到内存。 我们之前的操作都是基于内存,因此性能很高,然而一旦关闭程序,那么数据就丢失了。因此我们需要在指定的时间间隔内将内存的数据写入到磁盘,也就是行话讲的 Snapshot 快照,它恢复时会再将快照文件写入到内存里面。 这也是 Redis 和 Memcached 的主要区别之一,因为 Memcached 不具备持久化功能。而数据持久化,Redis 为我们提供了以下几种方式:
由于每种持久化方案,都有特定的使用场景,我们分别介绍。 RDB 持久化 RDB(Redis DataBase)是将某一个时刻的内存快照(Snapshot),以二进制的方式写入磁盘的过程。内存快照就是我们上面说的,它指内存中的数据在某一个时刻的状态记录,类似于拍照片,当你给朋友拍照时,一张照片就能把朋友一瞬间的形象全部记录下来。 而触发 RDB 的方式也分为两种:一类是手动触发,另一类是自动触发。 1)手动触发 手动触发持久化的操作有两个:save 和 bgsave ,它们主要区别体现在:是否阻塞 Redis 主线程的执行。 在客户端中执行 save 命令,就会触发 Redis 的持久化,但同时也会使 Redis 处于阻塞状态,直到 RDB 持久化完成,才会响应其他客户端发来的命令,所以在生产环境一定要慎用。
save 执行命令的流程如图所示: 而执行 bgsave(background save)则会后台保存, 它和 save 命令最大的区别就是 bgsave 会 fork 一个子进程来执行持久化(和父进程共享内存数据)。整个过程中只有在 fork 子进程时有短暂的阻塞,当子进程被创建之后,Redis 的主进程就可以响应其他客户端的请求了,相对于整个流程都阻塞的 save 命令来说,显然 bgsave 命令更适合我们使用。
bgsave 执行命令的流程如图所示: 2)自动触发 说完手动触发之后,再来看看自动触发,关于自动触发的条件我们是可以在配置文件中进行配置的。 save m n 是指在 m 秒内,如果有 n 个键发生改变,则自动触发持久化。参数 m 和 n 可以在 Redis 的配置文件中找到,例如 save 60 1 则表明在 60 秒内,只要有一个键发生改变,就会触发 RDB 持久化。 自动触发持久化,本质是 Redis 通过判断,如果满足设置的触发条件,自动执行一次 bgsave 命令。注意:当设置多个 save m n 命令时,满足任意一个条件都会触发持久化。例如,我们设置了以下两个 save m n 命令:
当 60s 内如果有 10 次 Redis 键值发生改变,就会触发持久化;如果 60s 内 Redis 的键值改变次数少于 10 次,那么 Redis 就会判断 600s 内,Redis 的键值是否至少被修改了 20 次,如果满足则会触发持久化。 flushall 命令也可以触发 RDB 持久化,但会把 rdb 文件清空,在生产环境中一定慎用。 还有就是在 Redis 主从复制中,当从节点执行全量复制操作时,主节点会执行 bgsave 命令,并将 rbd 文件发送给从节点,该过程也会自动触发 Redis 持久化。 RDB 配置说明 合理的设置 RDB 的配置,可以保障 Redis 高效且稳定的运行,下面一起来看看 RDB 的配置项都有哪些? Redis 中可以使用命令查询当前配置参数,查询命令的格式为:config get xxx ,例如,想要获取 rdb 文件的存储名称,可以使用 config get dbfilename ,执行效果如下:
设置 RDB 的配置,可以通过以下两种方式:
rdb 文件恢复 当 Redis 服务器启动时,如果启动目录中存在文件 dump.rdb,就会自动加载 rdb 文件恢复持久化数据。如果没有 dump.rdb 文件,请先将 dump.rdb 文件移动到 Redis 的启动目录。当然 Redis 在启动时有日志信息,会显示是否加载了 rdb 文件。
到现在为止,我们已经知道 RDB 持久化分为手动触发和自动触发两种方式。并且 rdb 文件的恢复也很简单,只需要把 rdb 文件放到 Redis 的启动目录,在 Redis 启动时就会自动加载并恢复数据。 RDB 优缺点 优点:
缺点:
当然我们也可以禁用持久化,从而提高 Redis 的执行效率。如果对数据丢失不敏感的情况下,可以在 redis.conf 里面把 save 开头的那几个配置全给注释掉,禁止 rdb 文件持久化,但一般不会这么做。 快照时数据能修改吗 RDB 持久化是将当前内存中的数据保存到 rdb 文件中,相当于做了一个快照。但在快照期间,能修改数据吗? 在给别人拍照时,一旦对方动了,那么这张照片就拍糊了,所以我们希望对方保持不动。对于内存快照而言,我们也不希望数据 "乱动"。 举个例子,我们在时刻 t 给内存做快照,假设内存数据量是 4GB,磁盘的写入带宽是 0.2GB/s,简单来说至少需要 20s 才能做完。如果在时刻 t+5s 时,一个还没有被写入磁盘的内存数据 "A",被修改成了 "A1",那么就会破坏快照的完整性,因为 A1 不是时刻 t 时的状态。因此和拍照类似,我们在做快照时也不希望数据 "乱动",也就是不能被修改。 但如果快照执行期间数据不能被修改,是会有潜在问题的。对于当前例子来说,在做快照的 20s 时间里,如果这 4GB 的数据都不能被修改,Redis 就不能处理对这些数据的写操作,那无疑就会给业务服务造成巨大的影响。 你可能会想到,可以用 bgsave 避免阻塞啊,这里就要说到一个常见的误区了:避免阻塞和正常处理写操作并不是一回事。虽然主线程的确没有阻塞,可以正常接收请求,但是为了保证快照的完整性,它只能处理读操作,不能像正常情况那样处理写操作(修改正在执行快照的数据)。 但为了快照而暂停写操作,肯定是不能接受的。所以这个时候,Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。简单来说,bgsave 子进程是由主进程 fork 生成的,可以共享主进程的所有内存数据。bgsave 子进程运行后,开始读取主进程的内存数据,并把它们写入 rdb 文件。 此时,如果主线程对这些数据也都是读操作,那么主线程和 bgsave 子进程相互不影响。但如果主线程要修改一块数据,那么会先把这块数据复制一份,生成该数据的副本。然后 bgsave 子进程会把这个副本数据写入 rdb 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。 假设在时刻 t 发生了 RDB 持久化,即使在 t + 5 时将数据修改了也不影响。因为修改之前会先将数据复制一份,然后才会修改,而写入 rdb 文件的仍是时刻 t 的数据。这个技术就叫做写时复制。 这既保证了快照的完整性,同时也允许主线程对数据进行修改,避免了对正常业务的影响。但如果此时碰巧要修改大量的 key,那么也要将这些 key 拷贝一份出来,因此可能会造成 OOM。所以有经验的人都会建议,给 Redis 机器预留一部分内存,其目的就是为了避免大量的写时复制造成的 OOM。 快照应该多久生成一次 根据 Redis 配置文件我们得知,默认情况下如果 900 秒内有 1 次修改、300 秒内有 10 次修改、60 秒内有 10000 次修改,那么会进行快照生成。
但是问题来了,Redis 的配置是通用的,但对于当前的业务来说却未必是最适合的,那么我们应该多久做一次快照呢? 首先我们说 RDB 会有数据丢失的可能,因为它是每隔一段时间判断一次,如果条件满足,那么触发一次写快照。但问题是如果在数据修改之后、但还没有触发写快照时机器宕机了,那么数据就会丢失。举个例子: 如果想数据尽可能少的丢失,那么快照的时间间隔就设置的短一些,就类似于相机的连拍。这样一来,快照的间隔时间变得很短,丢失的数据的可能性也会大大降低。那么问题来了,我们可不可以每秒做一次快照呢?毕竟,每次快照都是由 bgsave 子进程在后台执行,也不会阻塞主线程。 这种想法其实是错误的,虽然 bgsave 执行时不阻塞主线程,但如果频繁地执行全量快照,也会带来两方面的开销。
那么,有什么其他好方法吗?显然我们可以做增量快照,所谓增量快照就是指做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。 假设第一次做完了全量快照,之后如果再做快照,我们只需要将被修改的数据写入快照文件就行。但这么做的前提是,Redis 需要记录哪些数据被修改了,而这个 "记住" 功能又需要 Redis 使用额外的元数据信息去实现,这又会带来额外的空间开销问题。 如果我们对每一个键值对的修改都做个记录,那么假设有 1 万个被修改的键值对,我们就需要有 1 万条额外的记录。而且有的时候键值对非常小,比如只有 10 字节,而记录它被修改的元数据信息,可能就需要 8 字节。此时为了 "记住" 修改而引入的额外空间开销就比较大,这对于内存资源宝贵的 Redis 来说,有些得不偿失。 到这里我们可以发现,虽然快照的恢复速度快,但快照的频率不好把握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,又会产生额外开销,那么有什么方法解决呢?那么接下来就引入 Redis 的另一种持久化方式 AOF,将 RDB 和 AOF 结合起来才是最佳的解决方案。 AOF 持久化 Redis 的持久化除了 RDB 还有 AOF,我们知道 RDB 每次会保存某个时间间隔的数据,而且要达到触发条件才会进行持久化。但是这样有一个风险,那就是在持久化之前机器突然宕机了,那么这个时间间隔内的最新数据就会丢失。比如 600s 秒内变化 10 个 key 才会持久化,但是当变化 9 个 key 的时候宕机了,那么这 9 个 key 的数据就丢失了。 可能会导致 Redis 服务意外终止的条件:
那么如何解决以上的这些问题呢?Redis 为我们提供了另一种持久化的方案 AOF。 AOF(Append Only File)指的是追加到文件,所以 AOF 我们可以猜测它应该类似于日志文件一样,事实上也确实如此。但它和我们熟悉的数据库的预写式日志(Write Ahead Log,WAL)不同,WAL 是先把修改的数据记到日志文件中,然后执行相关操作;而 AOF 正好相反,Redis 是先执行命令、将数据写入内存,然后才记录日志。 那为什么要先执行命令再记日志呢?要回答这个问题,我们要先知道 AOF 日志文件里面记录了什么内容。我们以 "set name satori" 这条命令为例,看看 Redis 收到之后会在 AOF 文件中记录什么东西吧? 其中 *3 表示当前命令中有 3 个部分,每个部分上面都会有一个 $数字,表示该部分占了多少字节,比如 $4 表示 name 这个 key 占了 4 个字节。 但为了避免额外的检查开销,Redis 在向 AOF 里面记录日志的时候,并不会对这些命令进行语法检查,因此要是先记日志再执行命令的话,日志中就有可能记录了错误的命令,Redis 在使用日志恢复数据时,就可能会出错。 而 AOF 这种方式,就是先让系统执行命令,只有命令能执行成功,才会被记录到 aof 日志文件中,否则系统就会直接向客户端报错,所以 Redis 使用 AOF 这一方式的一大好处就是可以避免出现记录错误命令的情况。 除此之外,AOF 还有一个好处:它是在命令执行后才记录日志,所以不会阻塞当前的写操作。 持久化的查询和设置 查询 AOF 启动状态 使用 config get appendonly 命令,如下图所示:
yes 表示启动、no 表示为启动。 开启 AOF 持久化 Redis 默认是关闭 AOF 持久化的,想要开启 AOF 持久化,有两种方式,分别是使用命令行和修改配置文件。 如果是命令行启动 AOF,直接通过 config set appendonly yes 命令即可,如下所示:
这种方式的优点是无需重启 Redis 服务,缺点是如果 Redis 服务重启,则之前使用命令行设置的配置就会失效。 如果是配置文件开启 AOF,只需要将appendonly no 改成 appendonly yes,然后重启服务即可生效。 如何触发 AOF 持久化 1)自动触发 有两种情况可以自动触发 AOF 持久化,分为是:"满足 AOF 设置的持久化策略触发" 和 "满足 AOF 重写触发"。其中,AOF 重写触发一会详细介绍,这里重点来说 AOF 持久化策略都有哪些。AOF 持久化策略,分为以下三种:
这三种配置可以在 Redis 的配置文件(redis.conf)中设置:
因为每次写入磁盘都会对 Redis 的性能造成一定的影响,所以要根据用户的实际情况设置相应的策略,一般设置每秒写入一次磁盘的频率就可以满足大部分的使用场景了。 2)手动触发 在客户端执行 bgrewriteaof 命令就可以手动触发 AOF 持久化,和 RDB 持久化类似,RDB 持久化会生成 dump.rdb 文件,AOF 持久化会生成 appendonly.aof 文件。 但是注意:在往 aof 文件中记录日志的时候,是由主线程来完成的,如果把日志文件写入磁盘时,磁盘写压力大,就会导致写盘很慢,进而导致后续的操作也无法执行了。 AOF 重写 AOF 是通过记录 Redis 的执行命令来持久化(保存)数据的,所以 aof 文件会随着时间变得越来越大,这样不仅增加了服务器的存储压力,也会造成 Redis 重启速度变慢,为了解决这个问题 Redis 提供了 AOF 重写的功能。 1)什么是AOF重写? 举个例子,我们设置了一个 String 类型的 key,并对它做了 99 次修改。如果不做 AOF 重写的话,那么持久化文件中就会有 100 条记录执行命令的信息。而 AOF 重写之后,只保留最后一条,这样就去除了所有的无效信息。 2)AOF重写的触发时机 触发 AOF 文件重写,要满足两个条件,这两个条件也是配置在 redis.conf 中的,它们分别是:
这两个值可以使用 config get xxx 命令查看:
只有同时满足这两个参数设置的条件,才会触发 AOF 文件重写。 3)AOF重写流程 首先 Redis 写入 AOF 是由主线程完成的,但重写则不一样,重写时会 fork 一个 bgrewriteaof 子进程,这也是为了避免阻塞主线程,导致 Redis 性能下降。 AOF 文件重写是生成一个全新的文件,并把当前数据的最少操作命令保存到新文件上,当这一切完成之后,Redis 再交换两个文件即可。由于主线程不阻塞,所以在重写的时候依旧可以处理命令,并且这些最新的操作也会被记录到新的 AOF 文件中。 AOF everysec 真的不会阻塞主线程吗? 当 Redis 开启 AOF 时,需要配置 AOF 的刷盘策略,基于性能和数据安全的平衡,一般会采用 appendfsync everysec 这种方案。Redis 主线程会将命令数据写入 AOF page cache,然后 Redis 的后台线程以 1 秒为间隔,将 AOF page cache 的数据刷到(fsync)磁盘上的 aof 文件里。这种方案的优势在于,把 AOF 刷盘的耗时操作,放到了后台线程中去执行,避免了对主线程的影响。 但事实上真的不会影响主线程吗?答案是否定的。其实存在这样一种场景:Redis 后台线程在执行 AOF page cache 刷盘(fysnc)时,如果此时磁盘 IO 负载过高,那么调用 fsync 就会被阻塞住。此时主线程仍然接收写请求进来,然后仍然会写入 AOF page cache,但是主线程会先判断,后台线程是否已刷盘成功(fsync),如果 fsync 没有执行完,那么主线程会一直阻塞。 那么主线程是如何判断的呢?很简单,后台线程在刷盘成功后,都会记录刷盘的时间,主线程会根据这个时间来判断,距离上一次刷盘已经过去多久了。整个流程是这样的:
通过分析我们可以发现,即使配置的 AOF 刷盘策略是 appendfsync everysec,也依旧会有阻塞主线程的风险。其实产生这个问题的重点在于,磁盘 IO 负载过高导致 fynsc 阻塞,进而导致主线程写 AOF page cache 也发生阻塞。所以,一定要保证磁盘有充足的 IO 资源,从而避免这个问题。 AOF everysec 真的只会丢失 1 秒的数据吗? 接着上面的问题继续分析,然后重点关注上面的步骤 4。也就是:主线程在写 AOF page cache 时,会先判断上一次 fsync 成功的时间,如果距离上次 fysnc 成功在 2 秒内,那么主线程会直接返回,不再写 AOF page cache。 这就意味着,后台线程在执行 fsync 刷盘时,主线程最多等待 2 秒不会写 AOF page cache。如果此时 Redis 发生了宕机,那么 aof 文件中丢失的是 2 秒的数据,而不是 1 秒。那么问题来了,Redis 主线程为什么要等待 2 秒不写 AOF page cache 呢? 其实,Redis AOF 配置为 appendfsync everysec 时,正常来讲,后台线程每隔 1 秒执行一次 fsync 刷盘,如果磁盘资源充足,是不会被阻塞住的。也就是说,Redis 主线程其实根本不用关心后台线程是否刷盘成功,只要无脑写 AOF page cache 即可。但是 Redis 作者考虑到,如果此时的磁盘 IO 资源比较紧张,那么后台线程 fsync 就有概率发生阻塞风险。 所以 Redis 主线程写 AOF page cache 之前,先检查一下距离上一次 fsync 成功的时间,如果大于 1 秒没有成功,那么主线程此时就知道 fsync 可能阻塞了。因此主线程会总共等待 2 秒不写 AOF page cache,其目的在于:
但代价就是,如果此时发生宕机,AOF 丢失的就是 2 秒的数据,而不是 1 秒。因此这个方案应该是 Redis 作者对性能和数据安全性所做的进一步权衡,但无论如何,这里我们只需要知道,即使 AOF 配置为每秒刷盘,在发生上述极端情况时,AOF 丢失的数据其实是 2 秒。 AOF 配置说明 AOF 的配置参数也都在 Redis 的配置文件中,配置参数和说明如下: 其中最重要的是 appendfsync 参数,用它来设置 AOF 的持久化策略,可以选择按时间间隔或者操作次数来存储 AOF 文件。 数据恢复 1)正常数据恢复 正常情况下,只要开启了 AOF 持久化,并且提供了正常的 appendonly.aof 文件,在 Redis 启动时就会自动加载 aof 文件并启动。 默认情况下 appendonly.aof 文件在 Redis 的启动目录下,当然我们也可以设置。 持久化文件加载规则:
在 AOF 开启的情况下,即使 aof 文件不存在,只有 rdb 文件,也不会加载 rdb 文件。 2)异常数据恢复 在 aof 文件写入时如果服务器崩溃,或者是 aof 存储已满的情况下,最后一条命令可能被截断,这就是异常的 aof 文件。在文件异常的情况下,如果修改配置文件,也就是将 aof-load-truncated 设置为 yes,Redis 在启动时会忽略最后一条命令,并顺利启动 Redis。 3)复杂异常数据恢复 aof 文件可能出现更糟糕的情况,aof 文件不仅被截断,而且中间的命令也被破坏,这个时候再启动 Redis 会提示错误信息并中止运行,错误信息如下:
出现此类问题的解决方案如下:
AOF 优缺点 AOF 优点:
AOF 缺点:
AOF 小结 AOF 保存数据更加完整,它可以记录每次 Redis 的键值变化,也就是通过逐一记录操作命令,在恢复时再逐一执行命令的方式,保证了数据的可靠性。但考虑到性能,也可以选择每秒保存一次数据。 AOF 的持久化文件更加易读,但相比二进制的 rdb 文件来说,所占的存储空间也越大。为了解决这个问题,AOF 提供自动化重写机制,直接根据数据库里数据的最新状态,生成这些数据的插入命令,作为新日志,最大程度的减少了 AOF 占用空间大的问题。 这个过程通过后台线程完成,避免了对主线程的阻塞。同时 AOF 也提供了很方便的异常文件恢复命令: redis-check-aof --fix ,为使用 AOF 提供了很好的保障。 混合持久化 我们说 Redis 的持久化有 RDB 和 AOF,这两者的特点以及优缺点我们再来简单复习一下。 同步策略:
存储内容:
优点:
缺点:
所以为了能同时使用 RDB 和 AOF 各种的优点,Redis 4.0 之后新增了混合持久化的方式。在开启混合持久化的情况下,AOF 重写时会把 Redis 的持久化数据,以 RDB 的格式写入到 aof 文件的开头(写入值),之后的数据再以 AOF 的格式追加到文件的末尾(写入命令)。 这个方法既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的简单优势,颇有 "鱼和熊掌可以兼得" 的感觉,建议在实践中用起来。 开启混合持久化 查询是否开启混合持久化可以使用 config get aof-use-rdb-preamble 命令:
其中 yes 表示已经开启混合持久化,no 表示关闭,Redis 5.0 默认值为 yes。如果是其它版本的 Redis 首先需要检查一下,是否已经开启了混合持久化,如果没有开启,可以通过以下两种方式开启:
另外关于 AOF 和 RDB 的选择问题,有三点建议:
另外混合持久化的数据恢复和 AOF 持久化过程是一样的,只需要把 appendonly.aof 放到 Redis 的启动目录,在 Redis 启动时,只要开启了 AOF 持久化,Redis 就会自动加载并恢复数据。整个过程如下:
混合持久化的优缺点 混合持久化的优点:
混合持久化的缺点:
持久化最佳实践 持久化虽然保证了数据不丢失,但同时拖慢了 Redis 的运行速度,那怎么更合理的使用 Redis 的持久化功能呢?Redis 持久化的最佳实践可从以下几个方面考虑。 1)控制持久化开关 使用者可根据实际的业务情况考虑,如果对数据的丢失不敏感的情况下,可考虑关闭 Redis 的持久化,这样所以的键值操作都在内存中,就可以保证最高效率的运行 Redis 了。持久化关闭操作:
2)主从部署 使用主从部署,一台用于响应主业务,一台用于数据持久化,这样就可能让 Redis 更加高效的运行。 3)使用混合持久化 混合持久化结合了 RDB 和 AOF 的优点,Redis 5.0 默认是开启的。 4)使用配置更高的机器 Redis 对 CPU 的要求并不高,反而是对内存和磁盘的要求很高(也正因为如此 Redis 在 4.0 之前才是单线程的,当然现在也默认是单线程)。因为 Redis 大部分时候都在做读写操作,使用更多的内存和更快的磁盘,对 Redis 性能的提高非常有帮助。 小结 以上就是 Redis 的配置文件以及数据持久化,这篇文章的内容还是蛮多的,当然并不复杂。由于在介绍的过程中已经总结了,因此这里就不单独总结了。 另外 Redis 的配置并不只上面说的这些,比如还有慢日志等等,后续在介绍其它内容的时候再单独说。 本文参考自:
|
|