当我们买来一台机器时,首先需要看说明书,了解使用方式。同样对于Redis来说,通过查看配置文件,我们也可以大体了解Redis的组成部分和运行机制,从而更好的使用Redis。Redis配置文件中分成了不同的模块,我们也按照模块顺序学习。
# Redis内存单位,大小写不敏感。 # 1k => 1000 bytes # 1kb => 1024 bytes # 1m => 1000000 bytes # 1mb => 1024*1024 bytes # 1g => 1000000000 bytes # 1gb => 1024*1024*1024 bytes
# 引入其他配置文件,如果使用include引入配置文件 # include /path/to/local.conf # include /path/to/other.conf
# 启动时加载模块,如果server加载模块失败,会中断加载操作。 # loadmodule /path/to/my_module.so # loadmodule /path/to/other_module.so
# 设置允许连接的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
# 是否以守护进程的模式运行,改为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
由于Redis是内存数据库,断电即失,为了防止宕机后数据丢失,需要将内存数据保存到硬盘上。Redis提供了两种方式保存,一种是这里的SnapShot
快照,将内存中的全部数据保存到硬盘上,该文件称为RDB
文件(Redis DataBase),宕机重启后将RDB
文件加载到内存;另一种是AOF
(Append Only File)日志,每次的更新操作完成后,将该操作对应的日志写到文件中,宕机重启后,挨个执行日志中的命令来恢复数据。这里我们首先看先RDB
相关的配置,AOF
的配置在后面。
# 由于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 ./
Redis是高可用的,需要保证服务不能中断,因此Redis提供了主从库模式,将一份数据保存到多个实例上,用于分担压力的同时,当master挂掉后,其他实例可以继续提供服务。因此我们需要考虑的是,如何保证多个实例之间数据的一致性,同时当master挂掉后,怎样选举一个新的master?
# 指定该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
# 设置同一时间最大客户端连接数,默认是10000 # 如果Redis Server 根据maxclients去配置进程文件限制失败,则最大客户端连接数设置为 进程文件限制数-32 (留32个连接给内部连接用) # 如果当前连接数到达maxclients,则新的连接会被关闭,并报错"max number of clients reached" maxclients 10000
# 设置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
# 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
# 我们通常说,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
这是Redis的另一种持久化方式,使用快照保存RDB文件的持久化方式我们在上面讨论过。
开启该配置后,Redis在执行每个更新操作后,会将该命令写入日志文件,当机器宕机时,可以挨个执行日志中的命令恢复数据。如果使用这种方式,即使机器宕机,相对于RDB快照文件,丢失的数据很少。但是由于每个更新操作都写一次日志,会导致日志文件特别大。
# 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
欢迎访问我的博客:https://lifelmy.github.io/,一起学习,一起成长。