redis是工作在内存中的缓存服务器,数据存放在内存中,当重启服务器后,内存的数据会丢失。redis能通过快照和写日志的方式,持久化数据到磁盘。重启后通过重新装载快照或者重放日志的方式恢复数据。redis有两种方式持久化数据。
RDB快照
简介
redis会根据当前的内存数据,生成一个RDB镜像文件。服务器重启后通过装载之前生成的RDB文件恢复数据。同时在主从架构中,主服务器通过向其他从服务器发送RDB文件,实现从服务器的全量数据同步。
触发
-
save配置选项
当redis在一段时间内,如果数据发生变化的数量超过save命令指定的数值时,会触发快照。
redis服务器进程会先通过fork,快速创建一个子进程。通过子进程生成RDB文件,主进程在这个过程中不会被阻塞,能正常响应客户端请求。当临时的RDB快照文件生成完成后,子进程会通知主进程,新的RDB文件会替换旧的RDB文件 -
使用客户端命令,bgsave
客户端发送bgsave命令到redis服务器,bgsave命令会进入执行队列等待执行,当redis服务器执行bgsave时,会快速fork子进程,并立即响应客户端“Background saving started”。虽然通过发送bgsave
命令持久化数据阻塞后面的命令执行,阻塞在fork一个子进程,但是创建一个子进程的时间非常快,这个阻塞的时间非常短。 -
使用客户端命令,save
客户端发送save命令给redis服务器,save命令会进入执行队列中等待执行。当redis服务器时,会将内存中的数据拷贝到临时RDB文件中,当临时rds文件生成完毕后,用新的RDB文件替换旧的RDB文件。redis服务器在执行save命名时会阻塞后面的命令,直到RDB文件生成完成。生成RDB文件是十分耗时的,会导致后面的客户端请求响应超时。
其他能触发RDB持久化的场景
- 从服务器进行全量复制
- debug reload 重启redis
- shutdown 关闭redis
AOF 日志
在使用RDB进行数据持久化具有两个缺点:
- 无法做到时间点恢复,在服务器宕机后对丢失一段段时间的数据
- 系能开销大。进行持久化时,需要创建子进程,消耗内存。频繁的自动进行持久化时会照成大量的IO请求。
为了解决这几个缺点,redis提供了AOF持久化数据的方式。redis会将引起数据发生变化的命令追加到一个文件中。服务器重启或者宕机后,通过重放AOF文件中的命令实现恢复,能够进行时间点还原。AOF恢复的速度要比RDB恢复速度忙。
同步AOF文件策略
redis提供了3中方式,用于同步AOF文件,通过配置appendfsync进行改变。
- always: 将命令写入文件缓冲区的同时,调用fsync,同步磁盘文件。
- everysec:每秒调用一次fsync,同步磁盘文件。
- no:由操作系统确定什么时候调用fsync,进行同步。
服务器挂了 | |
---|---|
always | 最多丢失一条命令 |
everysec | 丢失一秒命令 |
no | 不清楚 |
AOF文件重写
随着时间的推移,AOF文件会一直被追加数据,体积越来越大,会照成2个问题
- 占用磁盘空间大
- 进行恢复时,消耗的时间越多
redis提供的AOF文件重写机制,解决这两个问题,当AOF文件重写被触发时,会将内存中的数据回溯成命令,保存到AOF文件。
- redis 主进程会开启一个子进程进行AOF文件重写,之后能正常响应客户端请求。
- 子进程会根据当前的内存数据,回溯redis命令,写入AOF文件。
- 在子进程进行AOF重写的过程中,如果主进程会将引起数据发送改变的命令记录到AOF_buf 和AOF_rewrite_buf 中。AOF_buf是用于当AOF重写失败,能将进行重写过程中收到的命令,同步到旧的AOF文件中。AOF_rewrite_buf 用于当新的AOF文件生成后,能将进行重写过程中收到的命令,同步到新的AOF文件中。
- 临时AOF文件生成完成后会替换旧的AOF文件。
触发AOF文件重写的条件
- 使用客户端命令bgrewrite
- 服务器配置参数,自动触发重写
auto-aof-rewrite-min-size,只有AOF文件大于指定的文件大小才会触发重写
auto-aof-rewrite-percentage,增长幅度要超过指定的百分比后才会触发重写。
上门两个参数必须同时满足才能触发重写。
查看AOF文件信息
使用INFO Persistence命令查看
aof_current_size //当前AOF文件大小
aof_base_size//上次启动或者重写后AOF文件的大小
比较
RDB | AOF | |
---|---|---|
数据安全 | 会丢失一段时间的数据 | 最多丢失1秒数据 |
重启后数据恢复 | 快 | 慢,需要重放AOF文件记录的命令 |
文件体积 | 小 | 大 |
持久化对性能的影响 | 性能消耗大·,每次生成RDB文件都需要将内存中的数据遍历一遍,全部保存到文件中 | 小,只需要向AOF文件追加引起数据发生变化的命令 |
如果存在RDB文件AOF文件,redis会加载AOF文件的数据。
RDB建议
建议关闭RDB快照,不使用RDB进行数据持久化。因为RDB持久化的过程占用系统资源大。但是在从服务器进行全量复制时,主服务器还是会生成RDB文件传输给从服务器。
AOF建议
如果redis只是作为缓存服务器使用,在一些场景下可以不开启持久化功能。如果开启AOF进行持久化,建议AOF文件同步策略使用每一秒同步一次AOF文件,减少文件IO。
运维经验
fork系统调用
使用fork创建子进程,是一个阻塞的过程。客户端的请求命令会被阻塞。一般情况下,由于linux系统具有写时复制的机制,主进程在复制子进程时,不需要将主进程的内存数据进行拷贝,它们会共享内存数据,当主/子进程修改共享的数据时,才会进行拷贝。所以fork的执行是十分快速的。
优化fork
- 服务器的内存要充足
- 父进程占用的内存也大,fork的过程消耗的时间也就越长,通过设置maxmemory,限制redis占用内存。
- 设置内存参数/proc/sys/vm/overcommit_memory为1,不管当前是否有足够的物理内存,都直接分配给进程。
- 减少fork的频率。设置合适的自动触发RDB快照的策略。减少全量复制
子进程内存占用
AOF文件追加阻塞
- redis服务器进程将引起数据发生改变的命令写入aof文件缓冲,假如同步策略是每秒进行一次aof文件同步。redis在写入缓冲区后,会判断距离当前时间2秒内,是否将缓冲区的数据同步到文件中,如果2秒内已同步,继续处理下一个客户端命令。否则会等待aof文件同步,客户端的请求会被阻塞。这种现象称为aof追加阻塞。
- 准确来说,使用aof进行持久化,每秒进行同步aof文件,最多会丢失2秒数据。
- 可以通过命令 INFO Persistence 。查看aof_delayed_fsync计数器,这个计数器记录的发送aof追加阻塞的次数。