持久化

1、RDB

  • 概念
    RDB持久化可以在指定的时间间隔内生成数据集的时间点内存快照
  • 配置
    1、save 60 10000
    2、rdbcompression yes
    3、dbfilename "dump_6379.rdb"
    4、dir "/appdata/redis/savefile"(AOF同)
  • 命令
save  
    通过主进程,造成阻塞,期间不能执行任何命令
bgsave  
    fork()子进程后台进行
  • 优点
    1、恢复速度快,但载入过程中会令redis一直处于阻塞状态,直到载入完成;
    2、可压缩保存;
    3、可最大化Redis性能,父进程fork子进程完成保存操作。
  • 缺点
    1、数据非实时保存,易丢失部分数据;
    2、数据集大时,fork()操作耗时且消耗cpu。

2、AOF

  • 概念
    AOF 持久化记录服务器执行的所有写操作命令(append-only file)
  • 配置
1、appendfsync    
        1、always    
        2、everysec  
        3、no(由系统决定同步频率)  
2、appendonly yes  
3、appendfilename "appendonly.aof"  
4、auto-aof-rewrite-percentage 100  
   auto-aof-rewrite-min-size 64mb
  • AOF还原过程
  1. 创建一个不带网络连接的伪客户端,因为redis的命令只能在客户端上下文中执行;
  2. 从AOF文件中分析并读取一条写命令;
  3. 使用伪客户端执行被读出的写命令;
  4. 一直重复步骤2和步骤3,直到AOF文件的所有写命令被处理完毕为止。
  • aof重写机制

    1. AOF文件重写并不需要对现有的AOF文件进行任何读取、分析或者写入操作,这个功能是通过读取服务器当前数据库状态来实现的。首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是AOF重写功能的实现原理;
    2. 同时,为了解决重写期间有数据写入导致现有AOF和重写后的AOF数据不一致的问题,Redis设置了一个AOF重写缓冲区,Redis执行完一个命令后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区。
    3. AOF重写完成后,会向父进程发送一个信号,父进程将调用信号处理函数执行以下操作:
      1)将AOF重写缓冲区的所有内容写入新AOF文件中;
      2)对新的AOF文件改名,原子地覆盖现有的AOF文件,完成两个文件的替换;
      3)整个过程,只有信号处理函数执行时才会对Redis父进程造成阻塞。
  • aof重写命令
bgrewriteaof  fork()子进程重写aof文件
  • 优点
    1、较为实时,默认(everysec)至多丢失一秒数据
    2、redis-check-aof --fix 可修复AOF文件
    3、文件可读性强
    4、可进行安全的rewrite操作
  • 缺点
    1、体积较大
    2、根据fsync策略,AOF可能会导致redis速度低于RDB

3、优先级

  1. 优先AOF载入内存,只有关闭AOF功能时才会载入载入RDB文件恢复数据库;
  2. BGSAVE和BGREWRITE不可同时进,BGSAVE时发起BGREWRITE,后者会阻塞,等待BGSAVE完成后再开始,BGREWRITE时发起BGSAVE,会被拒绝。

4、写时复制(Copy-On-Write)

(1) fork()
fork会创建一个子进程,子进程的是父进程的副本。

(2) exec()
exec函数的作用就是装载一个新的程序(可执行映像)覆盖当前进程内存空间中的映像,从而执行不同的任务。如redis的子进程专门用于进行bgsave或bgrewrite操作。

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

(4) Copy-On-Write优缺点?
优点:

  • COW技术可减少分配和复制大量资源时带来的瞬间延时;
  • COW技术可减少不必要的资源分配。比如fork进程时,并不是所有的页面都需要复制,父进程的代码段和只读数据段都不被允许修改,所以无需复制。

缺点:

  • 如果在fork()之后,父子进程都还需要继续进行写操作,那么会产生大量的分页错误(页异常中断page-fault),这样就得不偿失。

(5) Copy-On-Write在redis上的应用

  • Redis在持久化时,如果是采用BGSAVE命令或者BGREWRITEAOF的方式,那Redis会fork出一个子进程来读取数据,从而写到磁盘中。
  • 总体来看,Redis还是读操作比较多。如果子进程存在期间,发生了大量的写操作,那可能就会出现很多的分页错误(页异常中断page-fault),这样就得耗费不少性能在复制上。
  • 在rehash阶段上,写操作是无法避免的。根据 BGSAVE 命令或 BGREWRITEAOF 命令是否正在执行, 服务器执行扩展操作所需的负载因子并不相同, 这是因为在执行 BGSAVE命令或 BGREWRITEAOF 命令的过程中, Redis 需要创建当前服务器进程的子进程, 而大多数操作系统都采用写时复制(copy-on-write)技术来优化子进程的使用效率, 所以在子进程存在期间, 服务器会提高执行扩展操作所需的负载因子, 从而尽可能地避免在子进程存在期间进行哈希表扩展操作, 这可以避免不必要的内存写入操作, 最大限度地节约内存。