Redis最常用的场景就是做缓存,把DB数据存储在内存,然后直接从内存读数据,这样系统响应就会很快。 风险是一旦服务器宕机,内存中数据将全部丢失。
最简单的解决方案是从后端DB恢复这些数据,但注意:
所以,对于Redis,实现数据持久化,避免从后端 DB进行恢复,很关键。
redis所有数据保存在内存,对数据的更新将异步保存到磁盘。
持久化的意义: 主要是做灾难恢复、数据恢复,可归类到高可用。
比如你的Redis宕机,你要做的事情是让Redis变得可用,尽快变得可用! 重启Redis,尽快让它对外提供服务,若你没做数据备份,即使Redis启动了,数据都没了!有啥可用的? 而且很可能,大量请求过来,缓存全部无法命中,造成缓存雪崩。然后MySQL宕机,你都没法去找数据恢复到Redis里面去,Redis的数据从哪儿来?就是从MySQL来的!
若把Redis的持久化做好,备份和恢复方案也做到,那么即使你的Redis故障,也可通过备份数据,快速恢复,一旦恢复立即对外提供服务。
而是在数据文件损坏后从数据备份或快照中恢复 RDB 就是这种情况
以在失败后通过日志恢复一致性。由于操作日志是按顺序追加写入的,因此不会出现无法恢复操作日志的情况 类似于 Mysql 的重做和撤消日志。
因此数据本身就是日志,因此永远不会出现数据无法恢复的情况 CouchDB 是一个很好的例子。AOF 类似这种情况
按指定时间间隔执行数据集的时间点快照存储,类似于MySQL Dump的 frm 备份文件。
在Redis内部一个定时器事件,每隔固定时间去检查当前数据发生的改变次数与时间是否满足配置的持久化触发的条件,如果满足则通过操作系统fork调用来创建出一个子进程,这个子进程默认会与父进程共享相同的地址空间,这时就可以通过子进程来遍历整个内存来进行存储操作,而主进程则仍然可以提供服务,当有写入时由操作系统按照内存页(page)为单位来进行copy-on-write保证父子进程之间不会互相影响。 缺点是快照只是代表一段时间内的内存映像,所以系统重启会丢失上次快照与重启之间所有的数据。
记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据(MySQL 的 binlog)。
AOF 会记录服务器接收的每个写操作,这些操作将在服务器启动时再次执行,以重建原始数据集。使用与Redis协议本身相同的格式记录命令,并且仅采用append-only
方式。当日志太大时,Redis可以在后台重写日志。类似于MySQL Binlog、Hbase HLog。在Redis重启时,通过回放日志中的写入指令来重构整个数据。
Redis4.0 开始的新特性。在混合使用中 AOF 读取 RDB 数据重建原始数据集,集二者优势为一体。
如果希望Redis仅作为纯内存的缓存来用,亦可禁用RDB和AOF。 可以在同一实例中同时使用AOF和RDB。这种情况下,当Redis重新启动时,AOF文件将用于重建原始数据集,因为它可以保证是最完整的。
最重要的是理解RDB与AOF持久性之间的不同权衡。如果同时使用RDB和AOF两种持久化机制,那么在Redis重启时,会使用AOF来重新构建数据,因为AOF中的数据更加完整!
Redis Server在有多db 中存储的K.V可理解为Redis的一个状态。当发生写操作
时,Redis就会从一个状态切换到另外一个状态。
基于全量的持久化就是在某个时刻,将Redis的所有数据持久化到硬盘中,形成一个快照。快照,顾名思义可以理解为拍照一样,把整个内存数据映射到硬盘中,保存一份到硬盘,因此恢复数据起来比较快,把数据映射回去即可,不像 AOF,一条条的执行操作命令。 当Redis 重启时,通过加载最近一个快照数据,可以将 Redis 恢复至最近一次持久化状态上。
快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为 dump.rdb。
save本身是单线程串行
方式执行,因此当数据量大时,可能会发生Redis Server的长时间卡顿。
其备份期间其他命令全部阻塞,无法执行,因此备份时期 数据的状态始终一致
。
若存在老的RDB文件,则新的会替换老的,时间复杂度O(N)。
再使用脚本初始化 500w 数据,等待后发现已经落盘:
bgsave 可由
bgsave命令在执行时,会fork
一个子进程。子进程提交完成后,会立即给客户端返回响应,备份操作在后台异步执行,期间不会影响Redis的正常响应。
对于bgsave来说,当父进程Fork完子进程之后,异步任务会将当前的内存状态作为一个版本进行复制
。在复制过程中产生的变更,不会反映在这次备份当中。
在Redis的默认配置中,当满足下面任一条件,会自动触发 bgsave 的执行:
配置 | seconds | changes |
---|---|---|
save | 900 | 1 |
save | 300 | 10 |
save | 60 | 10000 |
bgsave相对于save的优势是异步执行
,不影响后续命令执行。但Fork子进程,涉及父进程的内存复制,会增加服务器内存开销。当内存开销高到使用虚拟内存时,bgsave的Fork子进程会阻塞运行
,可能会造成秒级不可用。因此使用bgsave需要保证服务器空闲内存足够。
命令 | save | bgsave |
---|---|---|
IO类型 | 同步 | 异步 |
是否阻塞 | 阻塞 | 非阻塞(在fork时阻塞) |
复杂度 | O(N) | O(N) |
优点 | 不会消耗额外内存 | 不阻塞客户端命令 |
缺点 | 阻塞客户端命令 | 需要fork子进程,内存开销大 |
rdb.c文件执行流程:
关闭自动RDB:
dbfilename dump-${port}.rdb
dir /redisDataPath
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
O(n)
耗内存,copy-on-write策略。RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒。 执行 fork 时,os会使用写时复制,即 fork 函数发生的一刻父子进程共享同一内存数据。当父进程要更改其中某片数据时(如执行一个写命令),os会将该片数据复制一份以保证子进程数据不受影响,所以新的 RDB 文件存储的是执行 fork 一刻的内存数据。
容易丢失数据。一般RDB每隔5分钟,或者更长时间生成一次,若过程中Redis宕机,就会丢失最近未持久化的数据
当Redis重新启动时,会从本地磁盘加载之前持久化的文件。当恢复完成之后,再受理后续的请求操作。
命令 | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
体积 | 低 | 高 |
恢复速度 | 快 | 慢 |
数据安全性 | 丢数据 | 根据策略决定 |
量级 | 重量级 | 轻量级 |
Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,通过配置项 aof-use-rdb-preamble
开启)。
如果把混合持久化打开,AOF 重写时就直接把 RDB 内容写到 AOF 文件开头:
参考