Redis持久化
RDB
RDB是通过直接将K-V键值对保存在硬盘文件来持久化。
- 通过两个命令可以让服务器执行rdb操作(tips:SAVE和BGSAVE底层都是调用的rdbSave)
- SAVE:SAVE命令由主进程执行,所以当执行SAVE命令后,服务器将进入阻塞状态,只有当RDB文件生成完成后,才开始处理请求。
- BGSAVE:BGSAVE的RDB文件是fork出一个子进程来执行SAVE操作,此时redis服务器是非阻塞仍旧可以继续处理接受请求。
- 但是BGSAVE命令执行期间,服务器处理SAVE,BGSAVE,BGREWRITEAOF三个命令的方式会有所不同。
- SAVE:命令会被拒绝,服务器为了避免父子进程同时执行两个rdbSave调用,防止产生竞争条件。
- BGSAVE:理由同上。
- BGREWRITEAOF:不能同时执行,必须等一个先执行完了另一个才开始执行,这是从性能方面考虑,两个子进程同时执行大量的磁盘写入操作,影响性能。
- RDB文件没有手动载入的命令,服务器启动时会主动去读取RBD文件,同样在RDB文件载入时,服务器处于阻塞状态。
- 定时BGSAVE:设置参数让redis服务器定时生成RDB文件:
- save 900 1:900秒内有一次修改就生成,该配置项保存在server.saveparams中,redis的定时维护任务serverCron每隔100毫秒检查一次saveparams中的参数,如果满足就执行BGSAVE。
- RDB文件格式和分析这里就不赘述了,参考redis设计与实现第二版
AOF
AOF是将服务器接收到的命令保存在硬盘文件上来实现持久化。
- redis服务器的进程就是事件循环,这个循环中的文件事件负责接受客户端的请求,并回复,而时间事件则负责执行像serverCron这样需要定时运行的函数。
- 服务器在执行对数据库有修改的操作的时候会将命令存储到aof_buf里,所以服务器在每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,考虑是否将aof_buf缓冲区的内容写入和保存到AOF文件里。
- flushAppendOnlyFile的行为由服务器配置项appendfsync控制
- always:将所有命令都持久化到文件中。
- everysec:每秒更新,这是一个单独的线程控制的。(这是默认值)
- no:不将aof_buf中的刷新到aof文件中,什么时候刷新由系统自己决定。
- 此外还有个操作系统导致的数据不安全问题,当redis服务器要将缓冲中的命令刷新到AOF文件里时,操作系统执行write操作时,会将数据先写入write缓冲中,等到缓冲被填满或者超过指定时限后才刷入硬盘,redis为了解决这个问题提供了两个函数,fsync和fdatasync来强制让操作系统立即将数据写入硬盘文件。
- flushAppendOnlyFile的行为由服务器配置项appendfsync控制
- redis从aof恢复:redis服务器会开启一个不带网络连接的fake client,由于redis命令只能由客户端发起,所以开启一个假客户端来不断发送aof文件里的命令,由服务器执行,全部完成后服务器即恢复。
- AOF文件重写功能:
- 目的:为了解决不断累加的AOF文件过大的问题。
- 原理:aof_rewrite不会去分析或者载入曾经的AOF文件,而是直接读取数据库中的数据生成最少的命令加入到新的AOF文件里。
- aof_rewrite也由子进程执行。
- 在子进程进行rewrite操作的时候,客户端还会不断有命令进来,此时可能会导致数据库状态的不一致,redis为了解决这个问题会将在这期间接受到的命令同步发送给aof_buf和aof_rewrite_buf,当rewrite完成后子进程会发送一个信号通知父进程,父进程在接收到该信号之后会将aof_rewrite_buf中的命令写到新的AOF文件里,同时完成新旧AOF文件的替换(原子操作)。