关于redis的一些细节
(这位大佬写的十分详细,借鉴一下https://mp.weixin.qq.com/s/m7WEAC6juUYnA5yyKgR4uA)
一、redis的持久化
redis持久化机制有两种:RDB(快照)(Redis Database)、AOF日志(Append Only File)
1、快照(RDB):快照是内存数据的二进制序列化形式,在存储上非常紧凑
在redis中,生成RDB的方式有两种,一种使用save,另一种使用bgsave,但是底层实现,都是调用的同一个函数——rdbsave,只是调用方式不同
(1)save方法:直接调用rdbsave方法,此时会阻塞Redis主进程,直至快照文件的生成。
(2)bgsave方法:此方法会调用glibc函数fork一个子进程,快照持久化完全交给子进程处理,子进程调用rdbsave方法,父进程继续处理客户端请求。如果内存资源不足,fork失败返回0;fork成功后,父进程处理客户端请求,子进程处理快照写磁盘,他们共享内存的代码段和数据段,节约内存资源(进程分离的一瞬间,内存增长无明显变化)
问题:子进程做数据持久化,不会修改内存数据结构,其只对数据结构进行遍历读取,然后序列化到磁盘上。而在此时,父进程在服务客户端的请求时,对内存数据结构进行修改了,这种情况是怎么处理的?
答:操作系统的COW机制(Copy On Write)(写时复制技术)。出现这种情况,会使用COW机制进行数据段页面分离。数据段由很多操作系统的页面组合而成,当父进程对一个页面数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改,而此时子进程相应的页面没有变化,它看到的内存里的数据在进程产生的那一瞬间就凝固了,称之为 “快照” 。
问题:父进程持续的修改操作,会造成越来越多共享的页面被复制出来,内存持续增长怎么办?
答:内存确实会持续增长,但是不会超过原有数据内存的2倍大小。同时,redis里面的冷数据占比较高,很少出现所有页面都被分离的情况,被分离的页面只占其中一部分。
问题:在调用了bgsave方法后,有没有可能又调用了save方法?
答:在调用bgsave、或者save方法时,会提前判断bgsave方法是否在执行,若bgsave在执行,就不会再执行save或者bgsave命令。
问题:生成了rdb文件后怎么使用呢?
答:Redis在启动服务器的时候会调用rdbload函数,会把生成的RDB文件给加载到内存中来,在载入的期间,每载入1000个键就会处理一次已经到达的请求,但是只会处理publish、subscribe、psubscribe、unsubscribe、punsubscribe这个五个命令。其余的请求一律返回错误,直到载入完成。
快照的优缺点:直接搬运一下
2、AOF
由于RDB可能会造成数据丢失,redis提供了另外一种持久化机制。
AOF日志存储的是Redis服务器的顺序指令序列,AOF日志只记录对内存进行修改的指令记录!(与快照不同)
Redis在接收到客户端修改指令后,进行参数校验、逻辑处理,如果没问题,就立即将该指令文本存储到AOF日志中,也就是说,先执行指令才将日志存盘!
1、AOF记录过程:当客户端发送指令到Redis服务器后,只要命令成功执行,这个命令先写入aof_buf,Redis的AOF写入缓冲区(不会立即写入磁盘,因为频繁的IO操作,会大大降低性能),每隔100ms,会执行serverCron函数,同时会调用flushAppendOnlyFile函数。这个命令会调用 write将写入缓冲区的数据写入到AOF文件中,但是这个时候还是没有真正的落到磁盘上。这是OS为了提高写入文件的效率,会将数据暂时写入到OS的内存的缓冲区内,等到缓冲区被填满了或超过了指定的时间,才会调用fsync或者sdatasync真正的将缓冲区的内容写入到磁盘中。但是如果在这期间机器宕了,那么数据仍然会丢失。所以如果想要真正的将AOF文件保存在磁盘上,必须要调用上面提到的两个函数才行。