前言

当我们买来一台机器时,首先需要看说明书,了解使用方式。同样对于Redis来说,通过查看配置文件,我们也可以大体了解Redis的组成部分和运行机制,从而更好的使用Redis。Redis配置文件中分成了不同的模块,我们也按照模块顺序学习。

1
2
3
4
5
6
7
8
9

# Redis内存单位,大小写不敏感。
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes

Includes

1
2
3
4
5

# 引入其他配置文件,如果使用include引入配置文件
# include /path/to/local.conf
# include /path/to/other.conf

Modules

1
2
3
4
5

# 启动时加载模块,如果server加载模块失败,会中断加载操作。
# loadmodule /path/to/my_module.so
# loadmodule /path/to/other_module.so

Network

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 设置允许连接的IP,类似于白名单。如果不设置bind,则允许所有网络连接,这种是非常危险的,所以默认只允许本地访问。
# 在地址前加上"-"前缀,表示即使这个地址不可用,Redis依然可以成功启动。
# bind 192.168.1.100 10.0.0.1 允许这两个IP连接Redis
# 默认 bind 127.0.0.1 -::1
bind 127.0.0.1 -::1

# 保护模式,默认开启
# 当保护模式开启时,如果没有配置bind 或者 没有设置密码,只接受本地连接
# 只有确定在没有使用 bind 绑定网络接口且未配置身份验证的情况下,允许其它主机的客户端仍要连接到 Redis,才应该禁用保护模式
protected-mode yes

# Redis端口
port 6379

# 此参数确定了TCP连接中已完成队列(完成三次握手之后)的长度,
# 当然此值必须不大于Linux系统定义的/proc/sys/net/core/somaxconn值,默认是511,
# 而Linux的默认参数值是128。当系统并发量大并且客户端速度缓慢的时候,可以将这二个参数一起参考设定。
# 在高并发环境下你需要一个高backlog值来避免慢客户端连接问题
tcp-backlog 511

# 客户端空闲多少秒后,服务端侧断开连接,0代表不断开连接
timeout 0

# TCP 连接保活
# 如果该选项配置不为0,则Redis将周期性地向客户端发送ACK请求,以检查客户端是否已经挂掉,对于无响应的客户端则会关闭其连接,默认为300秒。
tcp-keepalive 300

General

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 是否以守护进程的模式运行,改为yes,否则无法后台启动
daemonize no

# 当Redis以守护进程方式运行时,Redis会把pid写入pidfile,默认"/var/run/redis.pid"
pidfile /var/run/redis_6379.pid

# 日志级别 (debug、verbose、notice、warning)
loglevel notice

# 指定日志文件名称,设置为空字符串表示使用标准输出。如果以守护进程方式运行,并且使用标准输出日志将会写入 "/dev/null"
logfile ""

# 通过syslog-enabled来控制是否将日志打印到syslog中,同时可以通过syslog-ident来指定syslog里的日志标识。
syslog-enabled no
syslog-ident redis

# 指定syslog设备,值可以是USER或LOCAL0-LOCAL7。具体可以参考syslog服务本身的用法。
syslog-facility local0

# 禁用内置的崩溃日志,该配置默认被注释掉,即默认启用日志记录,需要禁用去掉注释即可
crash-log-enabled no

# 崩溃时的内存检查,是上述崩溃日志记录的一部分,默认启用,禁用去掉注释即可
crash-memcheck-enabled no

# 数据库的数量,默认使用第0个数据库,你可以通过"SELECT 1”命令选择第一个数据库
databases 16

SnapShotting

由于Redis是内存数据库,断电即失,为了防止宕机后数据丢失,需要将内存数据保存到硬盘上。Redis提供了两种方式保存,一种是这里的SnapShot快照,将内存中的全部数据保存到硬盘上,该文件称为RDB文件(Redis DataBase),宕机重启后将RDB文件加载到内存;另一种是AOF(Append Only File)日志,每次的更新操作完成后,将该操作对应的日志写到文件中,宕机重启后,挨个执行日志中的命令来恢复数据。这里我们首先看先RDB相关的配置,AOF的配置在后面。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 由于Redis是内存数据库,断电即失,为了防止宕机后数据丢失,需要将内存数据保存到硬盘上
# save <seconds> <changes> 表示在多少秒内,至少有多少次更新操作,就把数据保存到硬盘上
# 如果不配置,Redis使用如下三种策略保存快照
# save 3600 1 : 3600秒(一小时)内至少有1次更新操作
# save 300 100: 300秒(5分钟)内至少有100次更新操作
# save 60 10000: 60秒内至少有10000次更新操作
# save "" 表示禁用快照
save <seconds> <changes>


# 默认情况下,如果RDB快照开启,并且最近的一次快照保存失败了,Redis会拒绝接收更新操作,以此来提醒用户数据持久化失败了,否则这些更新的数据可能会丢失。
# 当后台的快照操作恢复后,Redis会恢复接收更新操作。
# 当然,可以更改这个配置,当最近的快照操作失败时,允许Redis继续接收更新操作。
stop-writes-on-bgsave-error yes


# 是否启用RDB快照文件压缩存储
# 默认是开启的,当数据量特别大时,压缩可以节省硬盘空间,但是会增加CPU消耗,可以选择关闭来节省CPU资源,建议开启。
rdbcompression yes

# 在5.0版本后,保存和加载RDB文件,新增了校验功能,用于保证文件的完整性。开启这个选项会增加10%左右的性能损耗,如果追求高性能,可以关闭该选项。
rdbchecksum yes

# RDB文件名
dbfilename dump.rdb

# Redis主从全量同步时,通过RDB文件传输实现。如果没有开启持久化,同步完成后,是否要移除主从同步的RDB文件,默认为no,如果涉及法律合规或者考虑安全问题,可以设置为yes。(只有AOF和RDB持久化都关闭情况下,该配置才生效)
rdb-del-sync-files no

# 存放RDB文件和AOF文件的目录
dir ./

Replication

Redis是高可用的,需要保证服务不能中断,因此Redis提供了主从库模式,将一份数据保存到多个实例上,用于分担压力的同时,当master挂掉后,其他实例可以继续提供服务。因此我们需要考虑的是,如何保证多个实例之间数据的一致性,同时当master挂掉后,怎样选举一个新的master?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

# 指定该Redis实例作为masterip:masterport的从机(replica)
# master和replica之间的复制是异步的;但是也可以指定,在master的副本小于指定数量时,复制时停止接收写请求
# 当replica短暂断联时,Redis使用增量同步的方式(只接收断联后Master接收的更新操作),而不用全量同步(将Master的所有数据再重新复制一份)
# 主从同步是自动进行的,不需要人为参与
replicaof <masterip> <masterport>


#当master服务设置了密码保护时,slave服务连接master的密码
masterauth <master-password>


# 当replica与master断联,或者正在复制全量数据时,replica应对客户端的请求:
# (1)replica-serve-stale-data yes
#     replica依然接受客户端请求,此时返回的数据可能是过时的数据(master更新了新数据,但是该replica断联,没有及时更新),或者是空数据(第一次复制时,还没来得及将数据复制完成)
# (2)replica-serve-stale-data no
#     除执行“INFO, REPLICAOF, AUTH, PING, SHUTDOWN, REPLCONF, ROLE, CONFIG, SUBSCRIBE,
#     UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB, COMMAND, POST,
#     HOST and LATENCY”命令外,针对其他所有命令都会返回错误信息“SYNC with master in progress”
replica-serve-stale-data yes


# replica是否只读,默认只读
replica-read-only yes


# 主从复制是否使用无硬盘同步
# 当一个新的replica连接上master,或者一个replica断联时间过长后重新连接(无法使用增量同步),两种情况均需要使用RDB文件全量同步数据,此时有两种方式:
# 1. 使用硬盘:master将全量数据的RDB快照保存到硬盘上,然后把RDB文件发送给replica
# 2. 无盘复制:不保存RDB到硬盘上,直接传输RDB文件
# 如果使用硬盘,此时有多个replica需要同步数据,共享这一个RDB文件就可以了;如果使用无盘复制,需要对每个replica都顺序挨个复制一次。
# 针对无盘复制,Redis也做了优化,当有replica需要全量同步时,Master并不是马上发送数据,而是等几秒钟,看是否还有新的replica需要同步,这样可以并行发送,否则一次传输一旦开始后,后续来的replica只能等待本次同步完后才能开始。
# 何时使用无盘复制:磁盘速度缓慢,带宽较高的情况下
repl-diskless-sync no


# 无盘复制时,master开始传输RDB快照的等待时间,默认5秒。
# 一旦开始传输,后续到达的replica只能排队等待本次RDB传输完后再开始同步。如果Master等待几秒钟,可能会有多个replica到达,这样可以并行传输
repl-diskless-sync-delay 5



# 使用无盘复制时,replica接收到数据后如何加载
# 通常情况下,磁盘速度是比网络慢的,保存并加载RDB文件会增加耗时,但是直接从网络解析RDB会一直刷新数据库,因此提供如下三个选项
# 1. 将接收到的数据先保存到本地,传输完后再加载(默认)
# 2. 确保安全时,直接无盘加载
# 3. 将接收到的数据,先在内存中保存一个副本(占用内存,可能OOM)
repl-diskless-load disabled


# replica PING master 的周期,默认10s
repl-ping-replica-period 10


# 设置超时时间,包含三类
# replica角度,master SYNC传输的RDB数据的超时时间
# replica角度,master发送数据包或者ping的超时时间。 
# master角度,replica ACK ping的超时时间
# 需要确保超时时间大于repl-ping-replica-period
repl-timeout 60


# 是否禁用TCP_NODELAY
# 选择yes,禁用TCP_NODELAY,会使用较小带宽发送数据,replica收到数据会有延迟,Linux默认40ms
# 选择no,表示不禁用,即启用TCP_NODELAY,Redis使用较大带宽发送数据给replica,这样replica收到数据的延迟较小
# 默认为no,保证主从较低延迟,如果网络拥塞,可以选择yes。
repl-disable-tcp-nodelay no


# replication backlog:接收到更新请求时,master会多写一份数据到backlog,这是一个环形缓冲区,当replica短暂断开连接并重连后,不用进行全量同步,只需要同步断联后更新的那部分。
# 由于是环形缓冲区,当replica断联时间过长,之前的数据会被覆盖,此时就需要进行全量同步了。
# replication backlog size 越大,允许replica断联的时间就越长,默认1MB
repl-backlog-size 1mb


# 所有replica断联多长时间后,master释放backlog,默认3600s,0代表永不清空。
repl-backlog-ttl 3600


# Redis是高可用的,当master有问题掉线时,需要从所有replica中选一个当master。该配置代表replica的优先级,越小代表优先级越高,默认100,0代表永远不会被推选当master
# 例如三个replica的优先级分别为10,100,25,第一个replica会选择第一个。
replica-priority 100



# min-replicas-to-write,该配置指定,如果master的健康replica个数小于N,master则停止接收更新请求。默认为0,表示禁用该配置
# min-replicas-max-lag:延迟小于等于min-slaves-max-lag秒的slave才认为是健康的slave,默认为10秒。
min-replicas-to-write 3
min-replicas-max-lag 10

Clients

1
2
3
4
5
6

# 设置同一时间最大客户端连接数,默认是10000
# 如果Redis Server 根据maxclients去配置进程文件限制失败,则最大客户端连接数设置为 进程文件限制数-32 (留32个连接给内部连接用)
# 如果当前连接数到达maxclients,则新的连接会被关闭,并报错"max number of clients reached"
maxclients 10000

Memory Management

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 设置Redis可用的最大内存限制,单位字节。
# 如果到达内存限制,根据清除策略(maxmemory-policy)移除key-value来腾出空间
# 如果根据清除策略无法移除key,或者清除策略配置的是“不清除”,Redis将会对增加内存占用的命令,如SET、LPUSH报错,读操作不受影响。
# 需要注意的是,这个内存限制不包含master发送给replica命令的buffer。如果包含这个buffer,当内存满了的话,master删除一部分key用于清除内存,同时又需要把这些命令放到buffer中,这也会增加内存占用,可能导致内存还是满的,master又需要清除key,循环上述操作,最终可能导致清空数据库。因此设置内存限制时,需要比内存小,给buffer留出内存空间。
maxmemory <bytes>


# 内存占用到达限制后,数据清除策略
# volatile-lru: 利用LRU算法移除设置过期时间的key(Least Recently Used 最近最少使用)
# allkeys-lru: 利用LRU算法移除任何key
# volatile-lfu: 利用LFU算法移除设置过期时间的key(Least frequently used 最不经常使用)
# allkeys-lfu: 利用LFU算法移除任何key
# volatile-random: 随机移除一个设置过期时间的key
# allkeys-random: 随机移除一个key
# volatile-ttl: 移除一个最接近过期时间的key
# noeviction: 不移除任何key,只是返回一个写错误,默认选项
maxmemory-policy noeviction

# LRU、LFU 和 minimal TTL 都是近似算法,相对精确算法可以节省内存,可以通过该配置来调整速度或精确度
# maxmemory-samples 越小,速度越快,越不精确;反之越精确,但是占用较多CPU资源。
# 默认为5,是一个比较折中的配置。
maxmemory-samples 5


# 从Redis 5开始,最大内存限制只对master生效,对replica无效,即replica-ignore-maxmemory yes。
# 清除策略只会在master端进行,然后master把要清除key的命令发给replica。如果replica达到内存限制,master没有,replica也不会根据清除策略删除key
# 该配置保证了主从一致性,如果配置了replica可写,或者replica内存和master不一样等情况,可以改为false
replica-ignore-maxmemory yes


# Redis有两种方式发现key过期了:访问到该key时发现过期了,或者是后台线程扫描发现(该方式称为 active expire key)。
# 扫描尽量保证过期key数量不能超过内存数量的10%,并避免消耗超过25%的cpu资源
# 该配置默认为1,最大值为10。配置越大,扫描后内存中存在的过期key越少,但会占用较多CPU资源,增大系统延迟。
active-expire-effort 1

Lazy Freeing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21

# Redis有两种删除方式:同步删除和异步删除。
# DEL命令是同步删除,当删除命令来时,删除完数据才能处理其他命令。如果key对应的value较小,阻塞的时间较短;当时如果key对应的value较大,服务可能会阻塞秒级来删除数据。同时Redis提供了异步删除命令:UNLINK(对应DEL的非阻塞版本)、FLUSHALL ASYNC(对应FLUSHALL的非阻塞版本) 和 FLUSHDB ASYNC(对应FLUSHDB的非阻塞版本). 当收到命令后,Redis会启动一个线程去删除数据,不会阻塞。

# 使用阻塞或者非阻塞方式,控制权在用户手中。但是Redis Server有时也需要删除Key或者刷新整个数据库,因此提供用户配置,默认阻塞方式删除。具体场景和配置项如下,
# 1. 内存到达限制后,根据配置的清除策略删除key 
# 2. 过期Key需要删除
# 3. 部分指令的影响,比如set一个已存在的key,需要把之前的value删除 
# 4. replica全量复制时,需要先清空自身数据库

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

# 用户执行DEL命令时,Redis转为UNLINK命令执行
lazyfree-lazy-user-del no

# FLUSHDB、FLUSHALL 命令通过后面的SYNC和ASYNC标记,来区分同步或异步操作。如果没有提供标记的话,使用该配置。默认为no,即同步操作。
lazyfree-lazy-user-flush no

Threaded I/O

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12

# 我们通常说,Redis是单线程,主要是指Redis的网络 IO 和键值对读写是由一个线程来完成的,但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。

# 现在Redis提供了多线程处理读写的功能。由于写操作较慢,此前我们的解决办法是通过pipeline的方式,或者是使用集群分片的方式横向拓展。现在使用多线程,不用再考虑pipeline和分片,能够提升两倍速度。

# 默认多线程是禁用的,如果确保是由于CPU繁忙导致性能较差才开启。开启时,建议机器配置应多于4个核,同时开启后保持一个核的空余。 例如4个核,配置 2-3个 I/O线程;8个核,配置6个线程。
# 设置为1,相当于不开启多线程,只是用一个线程处理读写。
io-threads 4

# 开启多线程后,默认多线程只用于写,也可以配置用于读(多线程读作用不大)。
io-threads-do-reads no

Append Only Mode

这是Redis的另一种持久化方式,使用快照保存RDB文件的持久化方式我们在上面讨论过。

开启该配置后,Redis在执行每个更新操作后,会将该命令写入日志文件,当机器宕机时,可以挨个执行日志中的命令恢复数据。如果使用这种方式,即使机器宕机,相对于RDB快照文件,丢失的数据很少。但是由于每个更新操作都写一次日志,会导致日志文件特别大。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# Redis默认使用RDB快照进行持久化,这种方式需要将整个内存文件做个备份,频率不能太高,否则对Redis性能有较大影响。
# 但是如果在两次RDB备份过程中宕机了,会丢失分钟级别的数据,因此Redis提供了AOF持久化方案,至多丢失一个更新数据或者秒级数据(依赖配置)。
# RDB和AOF可以同时启用,如果启用了AOF,Redis重启时默认加载AOF文件。
# 默认禁用AOF,使用RDB
appendonly no

# AFO文件名
appendfilename "appendonly.aof"

# AOF日志落盘策略
# 一个更新命令执行完成后,Redis会接着将该命令写入AOF缓冲区(使用主线程),调用fsync()会让操作系统将缓冲区数据写入磁盘。Redis提供了三种缓冲区写磁盘时机:
# 1. always: 同步写回:每个写命令执行完,立马同步地将日志写回磁盘
# 2. everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘
# 3. no,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘

# 三种操作各有优劣:
# 1. always: 可以做到基本不丢数据(至多丢一个),但是每个写命令后都需要将日志落盘,影响主线程性能
# 2. no: 效率较高,但是由操作系统负责落盘,Redis无法控制,一旦宕机数据就会丢失
# 3. everysec: 折中方案,每秒落盘一次,兼顾效率和数据
appendfsync everysec


# 当开启了AOF,并配置的是always或者everysec策略,如果此时后台在进行大量I/O操作,调用fsync()落盘可能会被阻塞。
# 该配置指定:当后台在执行BGSAVE或者BGREWRITEAOF命令进行大量I/O时,是否停止落盘,默认为no,即继续落盘。
# 如果选择yes,即停止落盘,如果发生宕机,可能会导致至多30s的数据丢失。 
no-appendfsync-on-rewrite no


# AOF文件重写
# AOF是以文件的形式在记录接收到的所有写命令。随着接收的写命令越来越多,AOF文件会越来越大。因此Redis提供了AOF重写机制用于压缩文件(同一个key的多次更新命令,最终可以重写为写一个命令)。
# auto-aof-rewrite-min-size : AOF文件size大于这个配置时才能触发重写
# auto-aof-rewrite-percentage: AOF文件大小增长率(对比上次重写后的大小)大于该配置时,触发重写。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb


# 是否允许加载被截断的AOF文件。
# AOF文件可能由于宕机未完全写入,导致文件不完整,当Redis重启时,会加载AOF文件,如果此时发现文件不完整:
# 1. Redis退出,并提示错误信息,后续用户可以通过"redis-check-aof“工具修复AOF文件,然后再重启
# 2. 尽可能加载可用信息,丢弃错误数据
aof-load-truncated yes



# RDB和AOF混合持久化
# RDB是全量内存数据的复制,频繁生成RDB文件会对性能造成很大影响,发生宕机会影响分钟级别的数据,但是文件大小较小,加载较快;
# AOF是写操作日志,一秒一次落盘的操作对性能影响不大,发生宕机至多会影响秒级别的数据,但是如果只使用AOF,会导致日志文件太大,需要重写AOF
# 因此可以将两者结合起来:两次RDB快照中间的数据,使用AOF日志保存。这样既保证了数据不丢失,也提高了性能。
aof-use-rdb-preamble yes