下: redis调用fork ,现在有父子两个进程;子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令;父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题;当子进程把快照内容写入以命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件;现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。
这两种持久化方式有各自的特点,快照相对性能影响不大,但一旦崩溃,数据量丢失较大,而aof数据安全性较高,但性能影响较大,这就得根据业务特点自行选择了。
三、主从复制
redis的主从复制策略是通过其持久化的rdb文件来实现的,其过程是先dump出rdb文件,将rdb文件全量传输给slave,然后再将dump后的操作实时同步到slave中。
要使用主从功能需要在slave端进行简单的配置:
slaveof master_ip master_port #如果这台机器是台redis slave,可以打开这个设置。 slave-serve-stale-data no #如果slave 无法与master 同步,设置成slave不可读,方便监控脚本发现题。如果是master--slave(master)--slave这种主从模式的话和master --slave 这种模式是相同的所以配置文件和是和master--slave 一样进行配置就可以。
配置好之后启动slave端就可以进行主从复制了,主从复制的过程大致如下:
Slave端在配置文件中添加了slaveof指令,于是Slave启动时读取配置文件,初始状态为REDIS_REPL_CONNECT;Slave端在定时任务serverCron(Redis内部的定时器触发事件)中连接Master,发送sync命令,然后阻塞等待master发送回其内存快照文件(最新版的Redis已经不需要让Slave阻塞);Master端收到sync命令简单判断是否有正在进行的内存快照子进程,没有则立即开始内存快照,有则等待其结束,当快照完成后会将该文件发送给Slave端;Slave端接收Master发来的内存快照文件,保存到本地,待接收完成后,清空内存表,重新读取Master发来的内存快照文件,重建整个内存表数据结构,并最终状态置位为 REDIS_REPL_CONNECTED状态,Slave状态机流转完成;Master端在发送快照文件过程中,接收的任何会改变数据集的命令都会暂时先保存在Slave网络连接的发送缓存队列里(list数据结构),待快照完成后,依次发给Slave,之后收到的命令相同处理,并将状态置位为 REDIS_REPL_ONLINE。
整个复制过程完成,流程如下图所示:
从以上的复制过程中可以发现,Slave从库在连接Master主库时,Master会进行内存快照,然后把整个快照文件发给Slave,也就是没有象MySQL那样有复制位置的概念,即无增量复制,如果一个master连接多个slave,就会比较影响master性能了。
四、数据备份策略
具体的备份策略是可以很灵活的,比如可以大致如下:
为了提高master的性能关闭master的持久化机制,即不进行快照也不进行aof,而是在凌晨访问量低的时候定时的用bgsave命令进行快照,并将快照文件保存到备份服务器上;slave端开启aof机制,并定时的用bgrewriteaof 进行数据压缩,将压缩后的数据文件保存到备份服务器上;定时的检查master与slave上的数据是否一致;当 master出问题并需要恢复时,如果采用master的备份快照恢复直接将备份的dump.rdb拷贝到相应路径下重启即可;如果要从slave端恢 复,需要在slave端执行一次快照,然后将快照文件拷贝到master路径下然后重启即可。不过有一点需要注意的是,master重启时slave端数 据会被冲掉,所以slave端要在master重启前做好备份。
持久化磁盘IO方式及其带来的问题
有Redis线上运维经验的人会发现Redis在物理内存使用比较多,但还没有超过实际物理内存总容量时就会发生不稳定甚至崩溃的问题,有人认为是基于快照方式持久化的fork系统调用造成内存占用加倍而导致的,这种观点是不准确的,因为 fork调用的copy-on-write机制是基于操作系统页这个单位的,也就是只有有写入的脏页会被复制,但是一般的系统不会在短时间内所有的页都发生了写入而导致复制,那么是什么原因导致Redis崩溃的呢?
答案是Redis的持久化使用了BufferIO造成的,所谓Buffer IO是指Redis对持久化文件的写入和读取操作都会使用物理内存的Page Cache,而大多数数据库系统会使用DirectIO来绕过这层PageCache并自行维护一个数据的Cache,而当Redis的持久化文件过大(尤其是快照文件),并对其进行读写时,磁盘文件中的数据都会被加载到物理内存中作为操作系统对该文件的一层Cache,而这层Cache的数据与Redis内存中管理的数据实际是重复存储的,虽然内核在物理内存紧张时会做 PageCache的剔除工作,但内核可能认为某块PageCache更重要,而让你的进程开始Swap,这时你的系统就会开始出现不稳定或者崩溃了。经验是当你的Redis物理内存使用超过内存总容量的3/5时就会开始比较危险了。
?
1、 快照的方式持久化到磁盘
自动持久化规则配置
save 900 1
save 300 10
save 60 10000
上面的配置规则意思如下:
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
redis也可以关闭自动持久化,注释掉这些save配置,或者save“”
如果后台保存到磁盘发生错误,将停止写操作.
stop-writes-on-bgsave-erroryes
使用LZF压缩rdb文件,这会耗CPU,但是可以减少磁盘占用.
rdbcompression yes
保存rdb和加载rdb文件的时候检验,可以防止错误,但是要付出约10%的性能,可以关闭他,提高性能。
rdbchecksum yes
导出的rdb文件名
dbfilename dump.rdb
设置工作目录, rdb文件会写到该目录,append only file也会存储在该目录下.
dir ./
Redis自动快照保存到磁盘或者调用bgsave,是后台进程完成的,其他客户端仍然和可以读写redis服务器,后台保存快照到磁盘会占用大量内存。调用save保存内存中的数据到磁盘,将阻塞客户端请求,直到保存完毕。
调用shutdown命令,Redis服务器会先调用save,所有数据持久化到磁盘之后才会真正退出。
对于数据丢失的问题:
如果服务器crash,从上一次快照之后的数据将