持久化
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还原过程
- 创建一个不带网络连接的伪客户端,因为redis的命令只能在客户端上下文中执行;
- 从AOF文件中分析并读取一条写命令;
- 使用伪客户端执行被读出的写命令;
- 一直重复步骤2和步骤3,直到AOF文件的所有写命令被处理完毕为止。
-
aof重写机制
- AOF文件重写并不需要对现有的AOF文件进行任何读取、分析或者写入操作,这个功能是通过读取服务器当前数据库状态来实现的。首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是AOF重写功能的实现原理;
- 同时,为了解决重写期间有数据写入导致现有AOF和重写后的AOF数据不一致的问题,Redis设置了一个AOF重写缓冲区,Redis执行完一个命令后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区。
- 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、优先级
- 优先AOF载入内存,只有关闭AOF功能时才会载入载入RDB文件恢复数据库;
- 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)技术来优化子进程的使用效率, 所以在子进程存在期间, 服务器会提高执行扩展操作所需的负载因子, 从而尽可能地避免在子进程存在期间进行哈希表扩展操作, 这可以避免不必要的内存写入操作, 最大限度地节约内存。
来源:oschina
链接:https://my.oschina.net/u/4359458/blog/4816389