zoukankan      html  css  js  c++  java
  • Redis持久化AOF与RDB快照

    【参考】

    《Redis深度历险 核心原理与应用实践》

    ---------------------------------------------------------------

    Redis所有的数据全部在内存中,如果突然宕机,内存中的数据就都会丢失,那么Redis是怎么保障数据不因故障丢失呢?
    【Redis的持久化策略】
    第一种是快照,第二种是AOF日志。
    所谓快照,就是将这一瞬间所有存于内存的数据全部保留下来,也就是一次性的全量备份。快照是内存数据的二进制序列化形式,在存储上很紧凑。
    AOF是将Redis服务器顺序指令序列,注意,AOF只记录对内存进行修改的指令记录。它是一个增量备份。
    我们可以想象以下,快照这种操作,可以将某一时刻内存的数据情况还原。而且每次有了新的快照就可以将历史快照丢弃,所以占用内存空间是随着使用情况而变化,稳定可控。但是在连续的两次快照之间,如果数据丢失那就无法还原了,而且快照这种操作是短时间记录大量的数据,如果某时刻服务器内的数据很多,那么此时一定会对CPU、IO较大负担。
    而AOF这种增量的事务性指令记录虽然每一条不多,但是存储会一直增长,好处是我们可以用一个空的Redis通过释放存储的AOF指令集还原Redis关闭前的状态,但这个过程会很漫长,所以需要定期进行AOF重写,只保留最小有效的指令集,减轻存储和还原过程的消耗。

    【快照原理】
    快照这一瞬间,Redis服务器需要将内存中的数据全部存入磁盘,而Redis又是单线程,那岂不是会因为文件IO操作造成服务器指令阻塞?
    但如果一边进行文件IO操作,一边响应客户端的请求,那么客户端来的新指令造成内存变化,那快照就不是那一瞬间的真实数据状态了,怎么处理呢?
    Redis使用了操作系统的多进程机制(COW--Copy On Write)来实现快照持久化。具体说,就是Redis在持久化时会调用Linux操作系统提供的fork函数产生一个子进程,快照持久化就交给子进程来处理,而父进程继续处理客户端的请求。
    fork一段时间内,子进程和父进程是共享物理空间(内存区)的,子进程的代码段,数据段和堆栈都指向父进程物理空间,即两者的虚拟空间不同,但物理空间其实是同一个。这一段时间内,内存的增长几乎没有明显变化,实际开销就是复制父进程的一个页表和为子进程创建一个进程描述符。
    此时,如果父进程中的指令对内存进行修改,那么父进程就会对将会被修改的页面复制一份分离出来,然后对这个副本进行修改,这就是所谓的只有Write的时候才会Copy,即Copy On Write。而此时,子进程还是老数据。
    随着父进程修改操作持续进行,越来越多的共享页面被分离出来,内存就会增长,但不会超过原有数据内存的2倍大小。一般来说,Redis里的冷数据占比较高,这一部分数据不会变化,也就是不会出现Copy数据页的情况,所以极少有所有的页面都被分离的情况。每个页面的大小是4KB,而一个Redis实例中一般都有成千上万个页面。
    子进程因为数据没有变化,所以能够完全地遍历在进程产生的那一瞬间的数据,形成快照。
    【AOF原理】
    Redis会在收到客户端的修改指令之后,进行参数校验、逻辑处理,如果没有问题,就立即讲这个指令文本存储到AOF日志中,也就是先执行,再存盘。而有的存储引擎如hbase/leveldb等是先存储再做逻辑处理。
    【AOF重写】
    AOF日志会随着Redis长期运行变得越来越长,所以为了恢复数据时减少AOF日志指令的执行时间,Redis提供了bgrewriteaof指令对AOF进行重写。原理是开辟一个子线程对内存进行遍历,转换成一系列的Redis操作指令,序列化到新的AOF日志文件中,序列化旧数据完成之后再将操作过程中发生的增量AOF日志追加到新的AOF日志文件中,追加完成后就用新的AOF文件代替旧的,重写完成。
    AOF的含义是ApendOnlyFile,而bgrewriteaof的含义是backgroud rewrite aof。
    【fsync】
    当对AOF日志文件进行写操作时,实际上是将内容写到了内核为文件描述符分配的一个内存缓存中,然后内核异步将数据刷到磁盘。这就意味着,这个过程中如果机器突然宕机,那么这个内存缓存中的数据就会丢失。
    Linux提供了fsync函数,可以强制将内核缓存中的内容刷到磁盘,但如果每一条指令进入都强刷执行IO操作的话,那么Redis的高性能就无从谈起了。所以Redis为了性能,通常配置1S左右执行一次fsync操作,这在保证高性能时,尽量少丢失数据。
    另外,Redis还可以配置永不调用fsync函数,让OS自主决定何时刷磁盘,但是这很不安全,另一个是来一次指令就调用一次fsync,这就导致Redis性能下降,生产环境基本不会使用。
    【运维】
    Redis主节点一般不会进行持久化操作,持久化操作主要在从节点进行。从节点是备份节点,没有来自客户端请求的压力,它的操作系统资源比较充沛。
    但如果出现网络分区,从长期连不上主,就会造成数据不一致,如果此时主节点宕机,那么数据就会丢失。
    所以为了数据安全,一方面要监控好网络,一方面还要再增加一个从节点降低网络分区的概率,只要有一个从节点同步正常,数据也不会轻易丢失。
    【Redis4.0混合持久化】
    重启Redis如果单纯使用rdb来恢复内存,虽然快,但会造成大量数据丢失;而使用AOF回放则需要很长的时间。
    Redis4.0使用快照加快照后的增量AOF解决了这个问题,增量AOF的体积比较小,所以回放很快。在Redis重启时,先用rdb加载当时的快照,再用增量AOF日志,这样效率就大大提升。

  • 相关阅读:
    实现 AD 采样,使用 LCD1602 显示 AD 数值
    数据结构(C语言)—排序
    Keil uVision4 创建51单片机工程
    51单片机 方波
    51单片机串口中断实验
    51单片机 中断控制蜂鸣器
    串口通信
    定时器与计数器
    中断系统
    《web前端设计基础——HTML5、CSS3、JavaScript》 张树明版 简答题简单整理
  • 原文地址:https://www.cnblogs.com/bruceChan0018/p/15706308.html
Copyright © 2011-2022 走看看