关于redis:Redis持久化

4次阅读

共计 4884 个字符,预计需要花费 13 分钟才能阅读完成。

Redis 作为一个内存数据库数据都存储在内存中,如果服务器重启那么内存中的数据将会失落。如果 Redis 作为缓存失落了数据没关系,能够从新加载;但如果是作为数据库,数据是相对不能失落的。那么存储层的长久化无非两种,一种是快照 / 正本,另外一种就是日志。Redis 同样为了防止数据失落提供了不同级别的的长久化形式,别离是 RDB 和 AOF。上面咱们对两种长久化形式剖析了解。

RDB

RDB 是一种 全量 的数据快照,是可能在指定工夫距离对你的数据进行 快照存储,默认的存储文件是dump.rdb。在 Redis 服务重启时,会加载该文件将数据恢复到内存中。

应用

RDB 应用的形式有三种。第一种是应用 save 命令生成 dump.rdb 文件;第二种是应用bgsave 命令生成dump.rdb 文件;第三种则是在配置文件中进行配置条件触发生成dump.rdb 文件。

  • save命令

客户端输出 save 命令进行长久化申请是一种同步形式。这种形式的毛病在于当执行该命令时,Redis 服务端会阻塞其余写申请直至实现同步。因而不倡议在生产环境应用,因为若数据量较大,同步则会耗时很久。罕用在后续不会再接管写申请时应用,例如服务停机保护等场景。

  • bgsave命令

bgsave 命令看起来和 save 命令很类似,但bgsave 命令是一种异步形式。这种形式不同于 save 的是 Redis 会 forks 出一个子过程进行数据长久化,父过程持续接管申请,当执行结束同步子线程敞开。

  • 配置文件触发

配置文件(redis.conf)中配置条件触发生成 dump.rdb 文件实际上也是执行 bgsave 命令,换句话说就是 配置触发bgsave 的规定,咱们看看默认的规定:

## 900 秒至多 1 次写的命令
save 900 1
## 300 秒至多 10 次写的命令
save 300 10
## 60 秒至多 10000 次写的命令
save 60 10000

这种形式的毛病就是如果工夫距离管制太大会造成数据失落,但太小又会导致频繁长久化,影响性能。
配置文件除了触发配置,rdb 文件还存在一些根底配置,如下所示:

## 是否压缩 rdb 文件
rdbcompression yes
## 如果为 yes 则示意,当备份过程出错的时候,主过程就进行进行承受新的写入操作
## 这样是为了爱护长久化的数据一致性的问题。stop-writes-on-bgsave-error yes
## rdb 文件的名称(单机不同端口启动服务器)dbfilename dump.rdb
## rdb 文件保留目录
dir /path/to/dump

工作形式

当 Redis 须要保留dump.rdb 文件时,服务器执行以下操作:

  • Redis 调用 forks 同时领有父过程和子过程。
  • 子过程将数据集写入到一个长期 RDB 文件中。
  • 当子过程实现对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。

这种工作形式使得 Redis 能够从写时复制(copy-on-write)机制中获益。

Copy-On-Write:如果有多个调用者同时要求雷同资源(如内存或磁盘上的数据存储),他们会独特获取雷同的指针指向雷同的资源,直到某个调用者试图批改资源的内容时,零碎才会真正复制一份专用正本给调用者,而其它调用者所见到的最后的资源依然放弃不变

长处

  • RDB 文件十分紧凑,它保留了某个工夫点的数据集,适宜数据备份;
  • 应用 fork 出子过程,能够最大水平的应用 redis 的性能;
  • RDB 长久化相似 java 中的序列化,复原速度相比 AOF 来的快。

    毛病

  • 会造成数据失落,因为在两个存储工夫点 A 和 B 之间 Redis 宕机,那么这个工夫窗口内的数据就会因为还没来得及存储而造成失落;
  • bgsave 命令须要 fork 出子过程,当数据集较大时,fork 的过程是十分耗时的, 可能会导致 Redis 在一些毫秒级内不能响应客户端的申请。

AOF

AOF 是一种 增量 的模式追加 记录每次对服务器写的操作,默认的存储文件appendonly.aof,是当服务器重启的时候会从新执行这些命令来复原原始的数据。

留神这里并不是间接存储 Redis 的写命令,而是这些写入操作以 Redis 协定的格局保留,因而 AOF 文件的内容非常容易被人读懂,对文件进行剖析(parse)也很轻松。

应用

AOF 的应用须要在配置文件中开启,默认是不开启 AOF 长久化的形式,配置文件对于 AOF 的配置如下所示:

## 是否开启 AOF yes 为开启 no 为不开启
appendonly yes

## aof 文件的名称
appendfilename appendonly.aof

## 三种写入策略
## always 每一个写申请写入 AOF 文件 即时将缓冲区内容写入 AOF 文件
appendfsync always
## everysec 每隔一秒写入 AOF 文件 每隔一秒将缓冲区内容写入 AOF 文件 默认策略
appendfsync everysec
## no 不负责写入 AOF 文件 交由操作系统决定 
## 一般来说,操作系统思考效率问题,会期待缓冲区被填满再将缓冲区数据写入 AOF 文件中
appendfsync no

长处

  • Redis 能够应用三种不同的 fsync 策略,数据不容易失落。
  • AOF 文件是一个只进行追加的日志文件,对服务器性能影响小。

    毛病

  • 对于雷同的数据集,文件的体积 AOF 要大于 RDB 且因为一直追加命令会以致 AOF 文件过大;
  • AOF 复原数据的速度相比于 RDB 慢。

    AOF 重写

    因为 AOF 一直追加命令导致 AOF 文件过大,为了解决这种问题所以 Redis 反对能够在不打断客户端的状况下,对 AOF 进行重写,假如你对一个 key increment了 100 次,实际上命令就能够重写为 set key 100。那么 Redis 对 AOF 重写有两种形式。

  • 在配置文件中配置是否开启重写,同样能够配置基于什么状况重写

    ## 默认不重写 aof 文件
    no-appendfsync-on-rewrite no
    ## aof 主动重写文件的百分比
    auto-aof-rewrite-percentage 100
    ## aof 主动重写文件的最小容量
    auto-aof-rewrite-min-size 64mb
  • bgrewriteaof 命令(客户端输出)

AOF 重写也是异步操作,同样 Redis 主过程 forks 出一个子过程来解决。重写的过程同样用到了写时复制(copy-on-write)机制,过程如下:

  • Redis 执行 fork(),当初同时领有父过程和子过程。
  • 子过程开始将新 AOF 文件的内容写入到临时文件。
  • 对于所有新执行的写入命令,父过程一边将它们累积到一个内存缓存中,一边将这些改变追加到现有 AOF 文件的开端, 这样样即便在重写的中途产生停机,现有的 AOF 文件也还是平安的。
  • 当子过程实现重写工作时,它给父过程发送一个信号,父过程在接管到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的开端,最初应用新的 AOF 文件替换掉旧的 AOF 文件。

    AOF 文件损坏

    在写入 AOF 文件时,Redis 服务器因为某些起因宕机则 AOF 文件会呈现谬误,在重启时 Redis 会回绝载入 AOF 文件,因而确保数据一致性,能够应用redis-check-aof 来修复这些问题。

    redis-check-aof -fix file.aof

    tips:备份原先的 AOF 文件,以防万一。(解决任何操作时最好都先备份)

RDB 和 AOF 混合长久化

那么 RDB 和 AOF 都有各自的长处和毛病,那么如何抉择比拟适合呢?RDB 的长处是文件体积小,复原数据速度快,但容易失落数据;而 AOF 的长处是不易失落数据,但文件体积过大。那么如果联合这两者的长处可能给出一个计划:既保证 RDB 文件体积小的前提下也能保障 AOF 的不容易失落数据是不是就能鱼和熊掌兼得呢?咱们后面也在介绍 RDB 和 AOF 的过程中也别离强调了 RDB 是全量备份,AOF 是增量备份。那么在 Redis4.0 之后提供这种长久化的形式,并且此形式为默认形式应用。

RDB-AOF 形式下,长久化策略首先将缓存中数据以 RDB 形式全量写入文件,再将写入后新增的数据以 AOF 的形式追加在 RDB 数据的前面,在下一次做 RDB 长久化的时候将 AOF 的数据从新以 RDB 的模式写入文件。这种形式既能够进步读写和复原效率,也能够缩小文件大小,同时能够保证数据的完整性。在此种策略的长久化过程中,子过程会通过管道从父过程读取增量数据,在以 RDB 格局保留全量数据时,也会通过管道读取数据,同时不会造成管道阻塞。能够说,在此种形式下的长久化文件,前半段是 RDB 格局的全量数据,后半段是 AOF 格局的增量数据。

过期 key 的淘汰策略

Redis 除了长久化数据到磁盘之外,那么长期在内存中的数据是如何保护清理的呢?通常过期策略如下三种。

  • 定时删除(被动行为)

用定时器来监督设置了过期工夫的 key,过期则删除该 key,这样对内存敌对但非常耗费 CPU 资源,影响缓存的吞吐量和响应工夫。

  • 惰性删除(被动行为)

当拜访一个 key 时,判断该 key 是否过期,若过期则删除。该策略节俭 CPU 资源但对内存不敌对。有可能存在过期 key 没有被拜访始终存在内存中的状况。

  • 定期删除

肯定工夫距离内随机扫描数据库肯定数量(非全副)带过期工夫的 key,删除其中曾经过期的 key。但该计划又会存在很多过期的 key 如果没有被随机到则会持续保留在内存中,所以Redis 中采纳了 惰性删除 + 定期删除的计划,这样在肯定水平上将 CPU 和内存的性能达到均衡。
Redis 具体做法可在其官网文档如下:

Specifically this is what Redis does 10 times per second:

  1. Test 20 random keys from the set of keys with an associated expire.
  2. Delete all the keys found expired.
  3. If more than 25% of keys were expired, start again from step 1.

内存回收策略

假如 Redis 在一直退出新的 key,然而之前的 key 也还没有达到过期工夫,随着 key 的越来越多,内存的空间曾经不够,那么 Redis 会怎么做呢?
首先,你能够通过在 Redis 的配置文件中指定maxmemory 来指定内存大小,或在运行中通过config set 动静设置内存大小。

## 设置 redis 存放数据的最大的内存大小
maxmemory <bytes>

对于 64 bit 的机器,如果 maxmemory 设置为 0,那么就默认不限度内存的应用,直到耗尽机器中所有的内存为止; 然而对于 32 bit 的机器,有一个隐式的闲置就是 3GB。

其次,如果内存曾经达到你的最大限度,那么能够在 Redis 的配置文件中应用maxmemory-policy 来配置内存回收策略。

## 配置 redis 回收策略
maxmemory-policy noeviction

Redis 总共提供了 6 种配置策略的形式,如下所示

  • volatile-lru: 在所有带有过期工夫的 key 中应用 LRU 算法淘汰数据;
  • alkeys-lru: 在所有的 key 中应用 LRU 算法淘汰数据,保障新退出的数据失常;
  • volatile-random: 在所有带有过期工夫的 key 中随机淘汰数据;
  • allkeys-random: 在所有的 key 中随机淘汰数据;
  • volatile-ttl: 在所有带有过期工夫的 key 中,淘汰最早会过期的数据;
  • noeviction: 不回收,当达到最大内存的时候,在减少新数据的时候会返回 error,不会革除旧数据,这是 Redis 的默认策略;

注:这里的 LRU 算法不是一种准确的 LRU 算法,而是通过采样的近似的 LRU 算法,在配置文件中能够通过maxmemory-samples 来设置采样大小,默认值为 5。官网提供的采纳比照如下:

为什么不采纳理论的 LRU 算法呢,官网文档给出了答案。

The reason why Redis does not use a true LRU implementation is because it costs more memory.

参考链接

Redis 官网中文文档 - 长久化
Redis 由浅入深深深深深分析
10 分钟彻底了解 Redis 的长久化机制:RDB 和 AOF
一文看懂 Redis 的内存回收策略和 Key 过期策略

正文完
 0