凌云的博客

行胜于言

Redis 配置详解(五)

分类:Redis| 发布时间:2019-04-11 19:39:00


概述

本文接着上一篇 Redis 配置详解(四) 继续讲解 Redis 的相关配置选项,这是 Redis 配置详解的最后一部分。

高级选项

hash-max-ziplist-entries 512
hash-max-ziplist-value 64

当哈希表的项不超过 hash-max-ziplist-entries,并且每一项的长度不超过 hash-max-ziplist-value 使用 ziplist 保存数据。

list-max-ziplist-size -2

Redis 的 List 内部是通过 quicklist 实现的(Redis 3.2 开始使用),quicklist 是一个双向链表。 quicklist 的每个节点都是一个 ziplist。list-max-ziplist-size 就是用于配置 quicklist 中的每个节点的 ziplist 的大小。 当这个值配置为正数时表示 quicklist 每个节点的 ziplist 所包含的元素个数是一个确定的数量。 当 list-max-ziplist-size 为负数时表示限制每个 ziplist 的大小,具体有以下含义:

  • -5:最大 64 kb <--- 正常环境不推荐
  • -4:最大 32 kb <--- 不推荐
  • -3:最大 16 kb <--- 可能不推荐
  • -2:最大 8 kb <--- 不错
  • -1:最大 4kb <--- 不错

默认值为 -2,也是官方最推荐的值,当然你可以根据自己的实际情况进行修改。

list-compress-depth 0

quicklist 中的 ziplist 节点会被压缩。为了 push/pop 操作的高效性,quicklist 的头和尾节点永远都不会被压缩。 list-compress-depth 选项用于控制 quicklist 中压缩的节点的深度,下面的示例中加了中括号的节点表示未压缩。

  • 0 表示不对节点进行压缩,这是默认的值
  • 1 表示对头和尾节点外的其他节点进行压缩, [head]->node->node->...->node->[tail]
  • 2 [head]->[next]->node->node->...->node->[prev]->[tail]
  • 3 [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail]
  • 依次类推
set-max-intset-entries 512

当 Redis 的集合类型保存的数据均为数字,并且元素个数不超过 set-max-intset-entries 的时候。 Redis 将使用特殊的 intset 结构来保存这个集合。

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

类似哈希表和列表,当排序集合的元素个数不超过 zset-max-ziplist-entries 并且每个元素的长度不超过 zset-max-ziplist-value 时,Redis 将使用 ziplist 保存这个排序集合。

hll-sparse-max-bytes 3000

HyperLogLog 稀疏模式的字节限制,包括了 16 字节的头,默认值为 3000。 当超出这个限制后 HyperLogLog 将有稀疏模式转为稠密模式。

将这个值设置为超过 16000 是没必要的,因为这时使用稠密模式更省空间。

stream-node-max-bytes 4096
stream-node-max-entries 100

用于设定 Streams 单个节点的最大大小和最多能保存多个个元素。

activerehashing yes

默认值为 yes。

当启用这个功能后,Redis 对哈希表的 rehash 操作会在每 100 毫秒 CPU 时间中的 1 毫秒进行。 Redis 的哈希表实现的 rehash 策略是一个惰性策略:就是说你对这个哈希表进行越多操作,你将有更多的 rehash 机会, 若你的服务器处于空闲状态则不会有机会完成 rehash 操作,这时哈希表会占用更多内存。

默认情况下会在每一秒中用 10 毫秒来对主哈希表进行 rehash。

如果在你的环境中需要有严格的延迟要求,则需要使用将 activerehashing 配置为 no,比如说需要在 2 毫秒内相应查询操作。 否则你应该将这个选项设置诶 yes,这样可以更及时地释放空闲的内存。

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

客户端输出缓冲区限制可用于强制断开从服务器读取数据的速度不够快的客户端 (一个常见的原因是 Pub/Sub 客户端处理发布者的消息不够快)。

可以为每种客户端设置不同的限制:

  • normal -> 普通客户端,包括 MONITOR 客户端
  • replica -> 复制客户端
  • pubsub -> 订阅了至少一个频道的客户端

client-output-buffer-limit 选项的语法为:

client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>

当一个客户端到达 hard limit 后会马上被断开,或者在到达 soft limit 并持续 soft seconds 秒后会被断开。

默认情况下,普通客户端不会有限制,因为除非主动请求否则他们不会收到信息, 只有异步的客户端才可能发生发送请求的速度比读取响应的速度快的情况。

默认情况下 pubsub 和 replica 客户端会有默认的限制,因为这些客户端是以 Redis 服务端 push 的方式接收数据的。

soft limit 或者 hard limit 都可以设置为 0,这表示不启用此限制。

client-query-buffer-limit 1gb

客户端查询缓冲区会累加新的命令。 默认情况下,他们会限制在一个固定的数量避免协议同步失效(比如客户端的 bug)导致查询缓冲区出现未绑定的内存。

但是,如果有类似于巨大的 multi/exec 请求的时候可以修改这个值以满足你的特殊需求。

proto-max-bulk-len 512mb

在 Redis 协议中,批量请求通常限制在 512 mb 内,可以通过修改 proto-max-bulk-len 选项改变这个限制。

hz 10

默认值是 10,范围是 1 到 500,超过 100 一般都不是一个好主意。 Redis 会通过调用内部函数来完成很多后台任务,比如关闭超时的客户端的连接,清除过期的 key,等等。

Redis 通过 hz 设置的值来决定执行这些任务的频繁程度。

hz 的默认值是 10,可以通过提高这个值来使得 CPU 在空闲的时候使用更多的 CPU 时间来处理后台任务。 但同时这会使得当有很多 key 在同一时间过期时,过期处理会更精确。

很多客户只有在一些需要很低延迟的环境中才会将这个值从 10 提升到 100。

dynamic-hz yes

通常来说根据连接上来的客户端数量对 HZ 的值按比例进行调整是有用的。 这很有用,例如,为了避免每次后台任务处理太多的客户端,从而避免高延迟峰值。

默认情况下 HZ 的值为 10,启用 dynamic-hz 后,当有大量客户端连接进来时 HZ 的值会临时性地调高。

启用 dynamic-hz 后,HZ 的配置值将作为基线,当有大量的客户端连接进来时,Redis 会将 HZ 的实际值设置为 HZ 的配置值的整数倍。 通过这种方式,空闲的 Redis 实例只会占用非常小的 CPU 时间,当实例变得繁忙时 Redis 能更快地进行响应(相对未启用 dynamic-hz 的情况)。

aof-rewrite-incremental-fsync yes

当子进程进行 AOF 的重写时,如果启用了 aof-rewrite-incremental-fsync, 子进程会每生成 32 MB 数据就进行一次 fsync 操作。 通过这种方式将数据分批提交到硬盘可以避免高延迟峰值。

rdb-save-incremental-fsync yes

当 Redis 保存 RDB 文件时,如果启用了 rdb-save-incremental-fsync 功能, Redis 会每生成 32 MB 数据就执行一次 fsync 操作。 通过这种方式将数据分批提交到硬盘可以避免高延迟峰值。

# lfu-log-factor 10
# lfu-decay-time 1

Redis LFU 回收策略(忘了的话可以回顾下 maxmemory 选项)是可以调整的。 在开始的时候使用默认值并且只有在经过对如何提升性能和 key LFU 随时间如何改变进行调查查后才对其更改是一个好的主意。 这可以通过 OBJECT FREQ 命令进行检查。

Redis 的 LFU 实现目前有两个可调整的参数:计数器对数因子(couter logarithm factor) 和 计数器衰退时间(counter decay time)。 在修改这两个参数之前理解这两个参数是很重要的。

每个 key 的 LFU 计数器只有 8 bits,也就是说最大值为 255,因此 Redis 通过对数行为来对计数进行概率性的增加。 当一个 key 被访问后,计数器通过如下方式进行增加(假设计数器的旧值为 old_value):

  • 取出一个 0 到 1 之间的随机数 R
  • 通过如下方式算出概率 P: 1 / (old_value * lfu_log_factor + 1)
  • 只有当 R < P 时,才增加计数器

lfu-log-factor 的默认值为 10。下表是不同计数器对数因子下计数器的改变频率:

factor 100 hits 1000 hits 100K hits 1M hits 10M hits
0 104 255 255 255 255
1 18 49 255 255 255
10 10 18 142 255 255
100 8 11 49 143 255

注意:上表是通过如下命令获得的: redis-benchmark -n 1000000 incr foo redis-cli object freq foo

注意2:计数器的初始值为 5

计数器衰减时间是 key 计数器除以 2 (如果值小于 <= 10,则递减)所必须经过的时间,单位为分钟。 lfu-decay-time 的默认值为 1。 0 表示每次都对计数器进行衰减。

在线碎片整理(active defragmentation)

警告:这个功能是实验性的。当然此功能已经在包括生产环境在内的环境中通过压力测试。 并且被多名工程师手工测过一段时间。

活动碎片整理允许 Redis 服务器压缩内存中由于申请和释放数据块导致的碎片,从而回收内存。 碎片是每次申请内存(幸运的是 Jemalloc 出现碎片的几率小很多)的时候会自然发生的。 通常来说,为了降低碎片化程度需要重启服务,或者至少需要清除所有的数据然后重新创建。 得益于 Oran Agra 在 Redis 4.0 实现的这个特性,进程可以在服务运行时以 “热” 方式完成这些目的。

通常来说当碎片化达到一定程度(查看下面的配置)Redis 会使用 Jemalloc 的特性创建连续的内存空间, 并在此内存空间对现有的值进行拷贝,拷贝完成后会释放掉旧的数据。 这个过程会对所有的导致碎片化的 key 以增量的形式进行。

需要重点理解的是:

  1. 这个特性默认是关闭的,并且只有在编译 Redis 时使用我们代码中的 Jemalloc 版本才生效。(这是 Linux 下的默认行为)
  2. 如果没有碎片问题,你永远不需要启用这项特性
  3. 如果你需要试验这项特性,可以通过命令 CONFIG SET activefrag yes 来启用

相关的配置参数可以很好的调整碎片整理过程。如果你不知道这些选项的作用最好使用默认值。

activedefrag yes

启用碎片整理。

active-defrag-ignore-bytes 100mb

有至少多少碎片时才开始碎片整理。

active-defrag-threshold-lower 10

有至少多少比例的碎片时才开始碎片整理。

active-defrag-threshold-upper 100

有多少比例的碎片时才开始以最大努力进行碎片整理。

active-defrag-cycle-min 5

进行碎片整理时至少使用多少比例的 CPU 时间。

active-defrag-cycle-max 75

最大努力进行碎片整理时使用多少 CPU 时间。

active-defrag-max-scan-fields 1000

进行主字典扫描时处理的 set/hash/zset/list 字段的最大数量(就是说在进行主字典扫描时 set/hash/zset/list 的长度小于这个值才会处理,大于这个值的会放在一个列表中延迟处理)。