凌云的博客

行胜于言

Redis 配置详解(三)

分类:Redis| 发布时间:2019-04-10 12:30:00


概述

本文接着上一篇 Redis 配置详解(二) 继续讲解 Redis 的相关配置选项。

内存管理

maxmemory <bytes>

设置 Redis 能使用的最大内存数,以字节为单位。根据你选择的过期策略(查看下面的 maxmemory-policy 选项), 当 Redis 使用的内存达到限制时,Redis 会尝试删除过期的键。

若 Redis 没有能删除的键,Redis 会拒绝那些如 SET,LPUSH 等会使用更多内存的命令,并且会正常相应那些如 GET 等只读命令。

这个选项通常用于将 Redis 作为 LRU 或者 LFU cache 使用的情况。

当你的 Redis 实例设置了 maxmemory 并且有 replicas 连接上来的情况,你需要留出一部分内存给 replica 缓冲区。

maxmemory-policy noeviction

当内存使用值到达 maxmemory 时使用的删除策略,默认值为 noeviction。

  • volatile-lru -> 对过期键使用 LRU(Least Recently Used) 近似算法
  • allkeys-lru -> 对所有键使用 LRU 近似算法
  • volatile-lfu -> 对过期键使用 LFU(Least Frequently Used)近似算法
  • allkeys-lfu -> 对所有键使用 LFU 近似算法
  • volatile-random -> 对过期键使用随机算法
  • allkeys-random -> 对所有键使用随机算法
  • volatile-ttl -> 删除最近过期的键(minimal TTL)
  • noeviction -> 对写请求返回错误,不删除键

注意:在内存到达限值,并且没有合适的键被删除的情况下,无论选择的是什么过期策略,Redis 都会返回出错。

maxmemory-samples 5

上面的 LRU,LFU 和 minimal TTL 算法都是近似算法,你可以通过改变这个选项来让算法更快还是更精确。 默认值是 5,也就是说 Redis 随机挑出 5 个键,然后选出一个最符合条件的。

对 LRU 来说 5 是比较合适的。10 已经很接近于真正的 LRU,但会消耗更多的 CPU。3 会更快但没有那么精确。

replica-ignore-maxmemory yes

从 Redis 5 开始,默认情况下,replica 节点会忽略 maxmemory 设置(除非在发生 failover 后,此节点被提升为 master 节点)。 这意味着只有 master 才会执行过期删除策略,并且 master 在删除键之后会对 replica 发送 DEL 命令。

这个行为保证了 master 和 replicas 的一致性,并且这通常也是你需要的,但是若你的 replica 节点是可写的, 或者你希望 replica 节点有不同的内存配置,并且你确保所有到 replica 写操作都幂等的,那么你可以修改这个默认的行为 (请确保你明白你在做什么)。

需要注意的是默认情况下 replica 节点不会执行过期策略,它有可能使用了超过 maxmemory 设定的值的内存。 因此你需要监控 replicas 节点所在的机器并且确保在 master 节点到达配置的 maxmemory 大小时, replicas 节点不会超过物理内存的大小。

惰性删除

lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no

Redis 有两种方式删除键。一种是使用如 DEL 这样的命令进行的同步删除。 同步删除意味着删除过程中服务端会停止处理新进来的命令。 若要删除的 key 关联了一个小的 object 删除耗时会很短。 若要删除的 key 管理了一个很大的 object,比如此对象有上百万个元素,服务端会阻塞相同长一段时间(甚至超过一秒)。

由于以上原因,Redis 同时提供了一种非阻塞的方式用于删除,比如 UNLINK(非阻塞的 DEL)以及用于 FLUSHALL 和 FLUSHDB 的 ASYNC 选项,这些命令能在后台回收内存。 这些命令能在常数时间内执行完毕。其他线程会在后台尽快回收内存。

DEL,UNLINK 以及用于 FLUSHALL 和 FLUSHDB 的 ASYNC 选项是用户可以控制的。 根据应用的设计,用户可以选择使用阻塞或者非阻塞的方式。 但是作为某些命令的副作用 Redis 服务端有时会删除某些 object 或者 flush 整个数据库。 特别是以下独立于用户操作的情形:

  1. 由于 maxmemory 和 maxmemory policy 配置导致的内存回收动作
  2. 由于过期,当一个 key 过期后(可以查看 EXPIRE 命令获取相关信息),必须回收其内存
  3. 由于某些命令的副作用,比如 STORE 命令,执行 STORE 命令可能需要删除已有的键。SET 命令需要删除已有的旧内容。
  4. 在复制过程中,当一个 replica 节点执行一个全量同步时,replica 需要删除整个数据库的内容以加载传输过来的 RDB 文件。

在上述所有情形中,删除 object 的默认行为都是以阻塞方式删除。当然你可以配置上述四个选项来改变这种默认行为。

APPEND ONLY 模式

appendonly no

默认情况下,Redis 会以异步形式将备份集 dump 到硬盘中。 对于很多应用来说,这种行为足够了,但是对于 Redis 进程崩溃或者断电的情况会导致最近数分钟的数据丢失(取决于 save 选项的设置)。

Append Only File 是 Redis 提供的另一种更好的持久化方式。 比如使用默认的数据同步策略(后面会讲),Redis 在断电等意外情况只会丢失最多一秒的写入数据, 在系统正常而 Redis 进程出错(如崩溃)的情况下只会丢掉最近一次写操作。

AOF 和 RDB 同步策略可以同时启用。当 AOF 启用后,Redis 在启动阶段会加载 AOF 文件, 这是因为相比 RDB,AOF 提供更好的持久性。 可以通过查看 http://redis.io/topics/persistence 获取更多信息。

appendfilename "appendonly.aof"

append only file 的名称,默认为 appendonly.aof。

appendfsync everysec

fsync() 调用用于告诉操作系统将数据写入硬盘而不是放入输出缓冲区中。 某些系统会马上将数据 flush 到硬盘中,而某些系统只是尽快尝试写入。 Redis 支持以下三种模式:

  • no 不调用 fsync,让操作系统决定什么时候真正写到硬盘
  • always 每次写入都对 append only file 进行 fsync 操作。最慢,也是最安全的选项。
  • everysec 每秒进行一次 fsync 操作,折中的做法。

默认选项为 "everysec",对安全性和速度进行了折中。 更多信息可以通过查看 http://antirez.com/post/redis-persistence-demystified.html 获取。

当 AOF fsync 策略设置为 always 或者 everysec 并且后台保存进程(bgsave 或者 AOF 日志重写)正在进行大量 I/O 操作, 某些 Linux 配置下,Redis 会阻塞太长时间在 fsync() 调用。目前,没有方法可以避免这种状况, 即使是在其他线程执行 fsync 操作也一样会阻塞我们的同步写 write(2) 操作。

no-appendfsync-on-rewrite no

为了缓和这种情况,可以在进行 BGSAVE 或者 BGREWRITEAOF 时禁止 fsync() 操作。 这意味着,当有子进程在保存的时候 Redis 的持久性相当于 "appendfsync none"。

当你的 Redis 延迟过大时可以将 no-appendfsync-on-rewrite 设置为 "yes", 否则将其保持在 "no" 以保证持久性。

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

自动重写 append only file 选项。 当 AOF 文件增长到一定比例后,Redis 可以自动通过隐式调用 BGREWRITEAOF 命令来重写 AOF 文件。

Redis 会记录上一次 rewrite 的 AOF 文件大小(若从未进行 rewrite,Redis 会使用启动时的 AOF 文件大小)作为基准大小。

Redis 会比较当前大小和基准大小,若当前大小大于一定比例则触发 rewrite。 为了防止增长比例到了但是总数据量还是非常小的情况就触发 rewrite,你还需要指定一个 AOF rewritten 的最小大小。

通过将 auto-aof-rewrite-percentage 设置为 0 可以禁用此功能。

aof-load-truncated yes

当 Redis 启动时可能会发现 AOF 文件被截断了(不完整),这可能是由于系统崩溃了, 特别是 ext4 没有以 data=ordered 选项挂载的情况(在 Redis 崩溃而系统正常的情况下不会发生截断)。

当这种情况发生时,Redis 可以选择终止进程,或者加载 AOF 文件上尽可能多的数据(目前的默认行为)。

当 aof-load-truncated 设置为 yes, Redis 服务端在启动的时候发现加载的 AOF 文件是被截断的会发送一条日志来通知客户。 若 aof-load-truncated 设置为 no,服务端会以错误形式终止进程并拒绝启动。 这是需要用户在重启服务前使用 "redis-check-aof" 工具来修复 AOF 文件。

注意:当 Redis 服务端发现 AOF 文件已经被损坏的情况下,服务端无论如何都会以错误终止进程。 这个选项只会在 Redis 尝试读取更多数据但是发现已经读到 AOF 文件的末尾时才会生效。

aof-use-rdb-preamble yes

当重写 AOF 文件时,Redis 可以使用 RDB 文件作为 AOF 文件的前导,这样可以更快地进行重写和恢复。 当启用这个功能时 AOF 文件由两部分组成:

[RDB file][AOF tail]

当加载 AOF 文件时,Redis 通过以 “REDIS” 字符串开头的 AOF 文件识别出此文件是由 RDB 和 AOF 组合而成的, Redis 会先加载 RDB 部分,然后再加载 AOF 部分。

LUA 脚本选项

lua-time-limit 5000

此选项用于控制 Lua 脚本的最长执行时间,单位为毫秒。

当 Lua 脚本的执行时间超出限制后,Redis 会在写入相关日志,并且向客户端返回出错。

当一个长时间运行的脚本超过超大限制后,只有 SCRIPT KILL 和 SHUTDOWN NOSAVE 命令是有效的。 前者可以用于停止尚未进行写操作的脚本。后者用于停掉服务, 当脚本已经开始进行写操作并用户于不想等脚本自然结束,这是唯一的方法。

将这个值设为 0 或者负数表示不限制最大运行时间。