1、Re d i s是一个ke y - va l u e存储系统(或缓存数据库); 2、Redis支持的存储的va l u e类型包括s t r i n g、l i s t、s e t、z s e t(s o r t e d s e t --有序集合)和h a s h。这些数据结构都支持p u s h / p o p、 3、Re d i s支持各种不同方式的排序。 3、为了保证效率,数据都是缓存在内存中,Re d i s会周期性的把更新的数据写入磁盘(RDB:以二进制的形式写入磁盘中,默认文件名为dump.rdb)或者把修改操作写入追加的记录文件(AOF), 并且在此基础上实现了m a s t e r - s l ave(主从)同步。 Redis 持久化 Redis的数据是全部存储在内存中的,为了避免机器突然宕机,数据全部丢失,因此需要持久化机制来保证数据不会因为宕机而丢失。 Redis 为我们提供了两种持久化方案,一种是基于快照(RDB),另外一种是基于 AOF 日志。 接下来就来了解一下这两种方案。 RDB持久化:在指定的时间间隔内生成数据集的时间点快照(point-in-time ); AOF持久化:将服务器收到的所有写操作命令记录下来,并在服务器重新启动的时候,重新执行这些写命令,利用这些命令来恢复数据集。 Redis同时使用 AOF 持久化和 RDB 持久化。 在这种情况下,当AOF重启时,会优先使用AOF文件去恢复原始数据。 因为AOF中保存的数据通常比RDB中保存的数据更加完整。 RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。 RDB 持久化 RDB(Redis Database) 通过快照的形式将数据保存到磁盘中。 所谓快照,可以理解为在某一时间点将数据集拍照并保存下来。 Redis通过这种方式可以在指定的时间间隔或者执行特定命令时将当前系统中的数据保存备份,以二进制的形式写入磁盘中,默认文件名为dump.rdb。 RDB的触发有三种机制,执行save命令;执行bgsave命令(备份命令);在redis.config中配置自动化。 bgsave 触发:为了不阻塞线上的业务,Redis就必须一边持久化,一边响应客户端的请求。 redis.config 配置:执行save或者bgsave命令都需要我们在客户端中去操作; 在生产情况下我们更多地需要是自动化的触发机制,那么Redis就提供了这种机制,我们可以在redis.config中对持久化进行配置: save 900 10 save 300 10 save “” 在redis.config中进行配置: save 900 1 是指在 900 秒内,如果有一个或一个以上的修改操作,那么就自动进行一次自动化备份; save 300 10 是指在 300 秒内 如果有十次或以上的修改操作,那么就进行数据备份,依次类推。 如果你不想进行数据持久化,只希望数据只在数据库运行时存在于内存中,那么你可以通过 save ""禁止掉数据持久化。 RDB 持久化相关的系数: stop-writes-on-bgsave-error:默认值为yes,即当最后一次 RDB 持久化保存文件失败后,拒绝接收数据。这样做的好处是可以让用户意识到数据并没有被成功地持久化,避免后续更严重的业务问题的发生; rdbcompression:默认值为yes,即代表将存储到磁盘中的快照进行压缩处理; rdbchecksum:默认值为yes,在快照存储完成后,我们还可以通过CRC64算法来对数据进行校验,这会提升一定的性能消耗; dbfilename:默认值为dump.rdb,即将快照存储命名为dump.rdb; dir:设置快照的存储路径。 RDB的优势以及它的劣势: 优势: RDB 是一个非常紧凑(compact)的文件(保存二进制数据),它保存了 Redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份: 比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本; RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心; RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作; RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。 劣势: 如果业务上需要尽量避免在服务器故障时丢失数据,那么 RDB 并不适合。 虽然 Redis 允许在设置不同的保存点(save point)来控制保存 RDB 文件的频率, 但是,由于RDB文件需要保存整个数据集的状态,所以这个过程并不快, 可能会至少5分钟才能完成一次RDB文件保存。 在这种情况下,一旦发生故障停机,就可能会丢失好几分钟的数据。 每次保存 RDB 的时候,Redis 都要 fork() 出一个子进程,并由子进程来进行实际的持久化工作。 在数据集比较庞大时,fork()可能会非常耗时,造成服务器在某某毫秒内停止处理客户端; 如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒。 虽然AOF重写也需要进行fork()但无论AOF重写的执行间隔有多长,数据的耐久性都不会有任何损失。 AOF 持久化 RDB持久化是全量备份,比较耗时,所以Redis就提供了一种更为高效地AOF(Append Only-file)持久化方案, AOF日志存储的是Redis服务器指令序列,AOF只记录对内存进行修改的指令记录。 在Redis服务器重新启动时,Redis就会利用AOF日志中记录的这些操作重新构建原始数据集(重新执行AOP文件中的命令)。 Redis会在收到客户端修改指令后,进行参数修改、逻辑处理,如果没有问题,就立即将该指令文本存储到 AOF 日志中,也就是说,先执行指令才将日志存盘。 这点不同于 leveldb、hbase等存储引擎,它们都是先存储日志再做逻辑处理。 AOF 的触发配置 AOF也有不同的触发方案,这里简要描述以下三种触发方案: always:每次发生数据修改就会立即记录到磁盘文件中,这种方案的完整性好但是IO开销很大,性能较差; everysec:在每一秒中进行同步,速度有所提升。但是如果在一秒内宕机的话可能失去这一秒内的数据; no:默认配置,即不使用 AOF 持久化方案。 可以在redis.config中进行配置,appendonly no改换为yes,再通过注释appendfsync配置需要的方案: appendonly no appendfilename “appendonly.aof” appendsync everysec ---- 每一秒中进行同步 appendsync always ---- 每次发生数据修改就会立即记录到磁盘文件中 appendsync no ---- 默认配置,即不使用 AOF 持久化方案 AOF 重写机制 随着Redis的运行,AOF的日志会越来越长,如果实例宕机重启,那么重放整个AOF将会变得十分耗时,而在日志记录中,又有很多无意义的记录,比如我现在将一个数据 incr 一千次,那么就不需要去记录这1000次修改,只需要记录最后的值即可。所以就需要进行 AOF 重写。 Redis 提供了bgrewriteaof指令用于对AOF日志进行重写,该指令运行时会开辟一个子进程对内存进行遍历,然后将其转换为一系列的 Redis 的操作指令,再序列化到一个日志文件中。完成后再替换原有的AOF文件,至此完成。 同样的也可以在redis.config中对重写机制的触发进行配置:通过将no-appendfsync-on-rewrite设置为yes,开启重写机制;auto-aof-rewrite-percentage 100意为比上次从写后文件大小增长了100%再次触发重写; auto-aof-rewrite-min-size 64mb意为当文件至少要达到64mb才会触发制动重写。 no-appendfsync-no-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb 重写也是会耗费资源的,所以当磁盘空间足够的时候,这里可以将 64mb 调整更大写,降低重写的频率,达到优化效果。 fsync 函数 再将AOF配置为appendfsync everysec之后,Redis在处理一条命令后,并不直接立即调用write将数据写入 AOF 文件,而是先将数据写入AOF buffer(server.aof_buf)。 调用write和命令处理是分开的,Redis只在每次进入epoll_wait之前做 write 操作。 Redis另外的两种策略,一个是永不调用 fsync,让操作系统来决定合适同步磁盘,这样做很不安全;另一个是来一个指令就调用 fsync 一次,这种导致结果非常慢。这两种策略在生产环境中基本都不会使用 AOF 的优劣 AOF 持久化的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多也只会丢失掉一秒钟内的数据; AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。 Redis 可以在 AOF 文件体积变得过大时,自动地在后台对AOF进行重写:重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失。 而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作。 AOF 文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子,如果你不小心执行了FLUSHALL命令,但只要AOF文件未被重写,那么只要停止服务器,移除 AOF文件末尾的 FLUSHALL 命令,并重启Redis ,就可以将数据集恢复到 FLUSHALL 执行之前的状态。 AOF 的缺点 对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积。 根据所使用的 fsync 策略AOF的速度可能会慢于RDB。 在一般情况下,每秒fsync的性能依然非常高,而关闭fsync可以让AOF的速度和RDB一样快,即使在高负荷之下也是如此。 不过在处理巨大的写入载入时RDB可以提供更有保证的最大延迟时间(latency)。 AOF在过去曾经发生过这样的bug :因为个别命令的原因导致AOF文件在重新载入时,无法将数据集恢复成保存时的原样。 混合持久化 重启 Redis 时,如果使用 RDB 来恢复内存状态,会丢失大量数据。而如果只使用 AOF 日志重放,那么效率又太过于低下。 Redis 4.0 提供了混合持久化方案,将RDB文件的内容和增量的AOF日志文件存在一起。 这里的AOF日志不再是全量的日志,而是自RDB持久化开始到持久化结束这段时间发生的增量AOF日志,通常这部分日志很小。 于是在Redis重启的时候,可以先加载RDB的内容,然后再重放增量AOF日志,就可以完全替代之前的AOF全量重放,重启后恢复数据效率因此得到大幅提升。