RDB、AOF、混合持久化是怎么回事
RDB快照(snapshot)
在默认情况下,Redis将内存数据库快照保存在名字为dump.rdb文件中。
需要注意的是,RDB 持久化是一种全量持久化方式,它将整个 Redis 数据集写入到磁盘。因此,在每次持久化操作期间,Redis 会将内存中的所有数据保存到 dump.rdb 中,而不是增量地向文件中添加数据。
rdb的启动方式:
save 900 1
save 300 10
save 60 10000 #在60秒的实践中10000个改动
在redis中的save命令可以手动持久化数据。
bgsave
(backgroundsave)后台save,其是通过操作系统提供的写时复制技术(Copy-On-Write,COW)实现的,在生成快照的同时,依然可以正常处理命令。
在Redis中,bgsave
命令用于在后台异步地创建当前数据库的快照。这个命令实际上会调用fork()系统调用来创建一个子进程,子进程会将数据写入磁盘。 在创建子进程时,父进程的内存空间会被复制到子进程。这是一个昂贵的操作,因为如果你有一个占用了10GB内存的Redis实例,那么执行fork()就需要额外的10GB内存。但是,这就是Copy-On-Write技术发挥作用的地方。
Copy-On-Write (COW) 是一种可以延迟或避免复制数据的技术。当父进程创建子进程时,操作系统并不立即复制所有的内存页,而是让父进程和子进程共享同样的内存页。只有当其中一个进程尝试修改某个内存页时,操作系统才会创建那个内存页的副本,让修改的进程(主进程)使用这个副本,而另一个进程(bgsave子进程)继续使用原来的内存页。这就是所谓的"写时复制"。
在Redis的BGSAVE命令中,COW技术可以帮助节省内存。当BGSAVE命令执行时,子进程开始写快照,而父进程继续处理命令。如果在此过程中,父进程需要修改某个内存页,那么操作系统会为父进程创建一个新的内存页,而子进程仍然可以看到原来的内存页,因此可以正确地将数据写入快照。
总的来说,COW技术允许Redis在创建快照时最大限度地节省内存,并且确保了快照的一致性,因为子进程看到的始终是fork()时的数据。
两者的区别如下。
缺点:
- 生成快照占用内存巨大。
- 按照快照的保存策略进行持久化,例如save 60 1000,如果在下一个60秒内没有满足save条件但是redis宕机了,那么就有数据丢失的问题。
AOF(Append-Only file)持久化
可以通过修改配置文件来打开AOF功能
# appendonly yes
将修改的每一条指令记录进文件appendonly.aof中(先写入os cache每隔一段时间fsync到磁盘),逐条的把所有命令执行。
可以配置redis多久fsync到磁盘一次:
appendfsync always #每次有新命令追加到AOF文件时就执行一次fsync
appendfsync everysec #每秒fsync一次,足够快,并且故障时只会丢失1秒钟的数据
appendfsync no #从不fsync,将数据交给操作系统来处理,足够快但是不安全。
推荐并且默认的就是每秒fsync一次,appendfsync everysec具体来说:
- Redis会用一个1秒计时器来实现这个时间间隔的控制。
- 在一个1秒时间段内,所有发生的写命令会存在内存缓冲区。
- 到了每个1秒时间点,Redis会把这1秒内缓冲起来的所有写命令一次性异步写入AOF文件。
- 然后计时器重置,开始计时下一个1秒时间段内的写命令。
缺点:redis运行时间很长,AOF文件会很大,恢复的速度会很慢。
RDB和AOF的优劣:
生产环境可以都启动
AOF重写:
incr readcount #多次执行,会在AOF文件中多次记录
set readcount n #不如直接set为最后一次的readcount的值
多条命令可以直接重写为一条命令。
#aof文件至少要达到64m才会自动重写,文件太小恢复速度本来就很快,重写意义不大
auto-aof-rewrite-percentage 100
#aof文件自上次重写后文件大小增长了100%会触发重写
auto-aof-rewrite-min-size 64mb
aof重写是执行bgrewriteaof命令重写aof,类似bgsave也是有些消耗性能。
Redis4.0 混合持久化
必须先开启AOF
aof-use-rdb-preamble yes
AOF在重写时,直接写成RDB的二进制格式数据,.aof文件中追加 快照的形式。
混合持久化的文件结构。
需要注意的是,这个RDB格式的快照是直接写入到AOF文件中的,而不是作为一个单独的文件存在。也就是说,一个AOF文件可能既包含RDB格式的数据快照,又包含普通的AOF命令。实际上,我们无法直接读取或者理解RDB格式的数据快照,因为它是二进制的。我们只能知道,当Redis加载这个AOF文件时,它会首先加载RDB格式的数据快照,然后再执行后面的命令,从而恢复所有的数据。
此时就不需要rdb持久化方式了。
优势:
- 数据格式更加紧凑,
- 数据启动恢复效率更高,
- 又兼顾安全性。
线上Redis持久化策略一般如何设置
如果对性能要求较高,在Master最好不要做持久化,可以在某个Slave开启AOF备份数据,策略设置为每秒同步一次即可。
一次线上事故,Redis主节点宕机导致数据全部丢失
如果你的Redis 采用如下模式部署,就会发生数据丢失的问题:
- master-slave+哨兵部署实例。
- master 没有开启数据持久化功能。
- Redis进程使用supervisor管理,并配置为进程宕机,自动重启。
如果此时master宕机,就会导致下面的问题:
- master宕机,哨兵还未发起切换,此时 master进程立即被supervisor自动拉起。
- 但master没有开启任何数据持久化,启动后是一个空实例。
- 此时 slave为了与master保持一致,它会自动清空实例中的所有数据,slave也变成了一个空实例。在这个场景下,master / slave 的数据就全部丢失了。
这时,业务应用在访问Redis时,发现缓存中没有任何数据,就会把请求全部打到后端数据库上,这还会进一步引发缓存雪崩,对业务影响非常大。
这种情况下我们一般不应孩给Redis主节点配置进程宕机马上自动重启策略,而应该等哨兵把某个Redis从节点切换为主节点后再重启之前宕机的Redis主节点让其变为slave节点。
Supervisor是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。它可以很方便的监听、启动、停止、重启一个或多个进程。用用Supervisor管理的进程,当一个进程意外被杀死,supervisort监听到进程死后,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。
Redis线上数据如何备份
- 写crontab定时调度脚本,每小时都copy一份rdb或aof文件到另一台机器中,保留最近48小时的备份。
- 每天都保留一份当日的数据备份到一个目录中