redis 持久化原理

redis 持久化的两种办法:

1、RDB

默认、二进制

  • save :

同步、阻塞

  • bgsave:

1)、异步、非阻塞 (fork() + copyonwrite)

2)、copyonwrite流程是怎样的?假如没有这种流程会怎样?

fork()之后,kernel把父进程中所有的内存页的权限都设为read-only,然后子进程的地址空间指向父进程。当父子进程都只读内存时,相安无事。当其中某个进程写内存时,CPU硬件检测到内存页是read-only的,于是触发页异常中断(page-fault),陷入kernel的一个中断例程。中断例程中,kernel就会把触发的异常的页复制一份,于是父子进程各自持有独立的一份。

3)、Redis中的CopyOnWrite

Redis在持久化时,如果是采用BGSAVE命令或者BGREWRITEAOF的方式,那Redis会fork出一个子进程来读取数据,从而写到磁盘中。
总体来看,Redis还是读操作比较多。如果子进程存在期间,发生了大量的写操作,那可能就会出现很多的分页错误(页异常中断page-fault),这样就得耗费不少性能在复制上。

而在rehash阶段上,写操作是无法避免的。所以Redis在fork出子进程之后,将负载因子阈值提高,尽量减少写操作,避免不必要的内存写入操作,最大限度地节约内存。

  • 自动触发

“save m n”。表示m秒内数据集存在n次修改时,自动触发bgsave

优势:

全量、适合灾备的快速恢复

劣势:

可能丢失数据(备份期间的修改不会被保存)

2、AOF

appenofaof、追加写、写命令

具体实现:aof持久化打开后,服务器在执行完一个命令后,会以协议格式将命令追加到aof缓冲区末尾,然后根据flushAppendOnlyFile函数去执行策略(具体策略根据配置决定)

  • always(每个时间循环都会将aof缓冲写入并同步aof文件)
  • everysec(每个时间循环都会将aof缓冲写步aof文件,如果上次同步时间距当前超过一秒,则进行同步,并且 这个操作由一个线程专门执行)
  • no (每个时间循环都会将aof缓冲写入aof文件,但不同步,所以故障会丢失)

(上述的同步即保存)

重写原理

在AOF文件文件越来越大时,使用bgrewriteaof重写aof文件:将全库数据以命令方式写入aof文件,类似快照(原aof文件,每行数据可能因为多次修改,存在多个aof修改记录,因此才去压缩命令、计算过期时间等aof比原来的文件要小)

重写期间数据不一致的问题

原因: 子进程单独读写,父进程此时对数据有更新,就会导致写完的aof文件与数据库状态不一致问题

解决方案:


Redis设置了一个缓冲区,写aof缓冲区时,同时写aof重写缓冲区,等aof文件写完后,子进程再给父进程发送个信号,父进程将重写缓冲区中的内容写入aof文件,并原子的覆盖。使得aof文件和数据库状态保持了一致。

优点:

数据不易丢失,尤其everysec

追加写、无磁盘寻址开销

可读性高、适合做紧急的灾后恢复

缺点:

同一份数据,aof比rdb要大

aof恢复比rdb要慢

注:部分内容源自《redis设计与实现》

你可能感兴趣的:(redis 持久化原理)