Redis的持久化主要有两大机制,即AOF日志和RDB快照
AOF日志
1.2 AOF日志是如何实现的?
说到⽇志,我们⽐较熟悉的是数据库的写前⽇志(Write Ahead Log, WAL)——例如mysql的redolog,也就是说,在实际写数据前,先把修改的数据记到⽇志⽂件中,以便故障时进⾏恢复。不过,AOF⽇志正好相反,它是写后⽇志,“写后”的意思是Redis是先执⾏命令,把数据写⼊内存,然后才记录⽇志,如下图所示:
 
那AOF为什么要先执⾏命令再记⽇志呢?
1、AOF⾥记录的是Redis收到的每⼀条命令,这些命令是以⽂本形式保存的。
2、为了避免额外的检查开销,Redis在向AOF⾥⾯记录⽇志的时候,并不会先去对这些命令进⾏语法检查。所以,如果先记⽇志再执⾏命令的话,⽇志中就有可能记录了错误的命令,Redis在使⽤⽇志恢复数据时,就可能会出错。
3、它是在命令执⾏后才记录⽇志,所以不会阻塞当前的写操作。
 
AOF两个潜在的⻛险
1、如果刚执⾏完⼀个命令,还没有来得及记⽇志就宕机了,那么这个命令和相应的数据就有丢失的⻛险。
2、AOF虽然避免了对当前命令的阻塞,但可能会给下⼀个操作带来阻塞⻛险。这是因为,AOF⽇志也是在主线程中执⾏的,如果在把⽇志⽂件写⼊磁盘时,磁盘写压⼒⼤,就会导致写盘很慢,进⽽导致后续的操作也⽆法执⾏了。
基于以上两点,如果我们能够控制⼀个写命令执⾏完后AOF⽇志写回磁盘的时机,这两个⻛险就解除了。
  • Always,同步写回:每个写命令执⾏完,⽴⻢同步地将⽇志写回磁盘;
  • Everysec,每秒写回:每个写命令执⾏完,只是先把⽇志写到AOF⽂件的内存缓冲区,每隔⼀秒把缓冲区中的内容写⼊磁盘;
  • No,操作系统控制的写回:每个写命令执⾏完,只是先把⽇志写到AOF⽂件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
 
AOF文档太大了怎么办?
随着输入的命令越来越多,这些命令都会被记录到AOF文件中,导致AOF文件过大。
 
AOF文件过大的问题:
系统发送宕机重启,从AOF文件恢复数据的速度很慢,影响业务。
占用系统磁盘
 
redis有AOF重写机制,当⼀个键值对被多条写命令反复修改时,AOF⽂件会记录相应的多条命令。但是,在重写的时候,是根据这个键值对当前的最新状态,为它⽣成对应的写⼊命令。
和AOF⽇志由主线程写回不同,重写过程是由后台线程bgrewriteaof来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
我把重写的过程总结为“⼀个拷⻉,两处⽇志”。
  • “⼀个拷⻉”就是指,每次执⾏重写时,主线程fork出后台的bgrewriteaof⼦进程。此时,fork会把主线程的内存拷⻉⼀份给bgrewriteaof⼦进程,这⾥⾯就包含了数据库的最新数据。然后,bgrewriteaof⼦进程就可以在不影响主线程的情况下,逐⼀把拷⻉的数据写成操作,记⼊重写⽇志。
  • “两处⽇志”⼜是什么呢?因为主线程未阻塞,仍然可以处理新来的操作。此时,如果有写操作,第⼀处⽇志就是指正在使⽤的AOF⽇志,Redis会把这个操作写到它的缓冲区。这样⼀来,即使宕机了,这个AOF⽇志的操作仍然是⻬全的,可以⽤于恢复。⽽第⼆处⽇志,就是指新的AOF重写⽇志。这个操作也会被写到重写⽇志的缓冲区。这样,重写⽇志也不会丢失最新的操作。等到拷⻉数据的所有操作记录重写完成后,重写⽇志记录的这些最新操作也会写⼊新的AOF⽂件,以保证数据库最新状态的记录。此时,我们就可以⽤新的AOF⽂件替代旧⽂件了。
 

 
Redis采⽤fork⼦进程重写AOF⽂件时,潜在的阻塞⻛险?
1:、fork⼦进程,fork这个瞬间⼀定是会阻塞主线程的(注意,fork时并不会⼀次性拷⻉所有内存数据给⼦进程),fork采⽤操作系统提供的写实复制(Copy On Write)机制,就是为了避免⼀次性拷⻉⼤量内存数据给⼦进程造成的⻓时间阻塞问题,但fork⼦进程需要拷⻉进程必要的数据结构,其中有⼀项就是拷⻉内存⻚表(虚拟内存和物理内存的映射索引表),这个拷⻉过程会消耗⼤量CPU资源,拷⻉完成之前整个进程是会阻塞的,阻塞时间取决于整个实例的内存⼤⼩,实例越⼤,内存⻚表越⼤,fork阻塞时间越久。拷⻉内存⻚表完成后,⼦进程与⽗进程指向相同的内存地址空间,也就是说此时虽然产⽣了⼦进程,但是并没有申请与⽗进程相同的内存⼤⼩。那什么时候⽗⼦进程才会真正内存分离呢?“写实复制”顾名思义,就是在写发⽣时,才真正拷⻉内存真正的数据,这个过程中,⽗进程也可能会产⽣阻塞的⻛险,就是下⾯介绍的场景。
fork出的⼦进程指向与⽗进程相同的内存地址空间,此时⼦进程就可以执⾏AOF重写,把内存中的所有数据写⼊到AOF⽂件中。但是此时⽗进程依旧是会有流量写⼊的,如果⽗进程操作的是⼀个已经存在的key,那么这个时候⽗进程就会真正拷⻉这个key对应的内存数据,申请新的内存空间,这样逐渐地,⽗⼦进程内存数据开始分离,⽗⼦进程逐渐拥有各⾃独⽴的内存空间。因为内存分配是以⻚为单位进⾏分配的,默认4k,如果⽗进程此时操作的是⼀个bigkey,重新申请⼤块内存耗时会变⻓,可能会产阻塞⻛险。另外,如果操作系统开启了内存⼤⻚机制(Huge Page,⻚⾯⼤⼩2M),那么⽗进程申请内存时阻塞的概率将会⼤⼤提⾼,所以在Redis机器上需要关闭Huge Page机制。Redis每次fork⽣成RDB或AOF重写完成后,都可以在Redis log中看到⽗进程重新申请了多⼤的内存空间。
 
AOF重写为什么新创建一个AOF日志文件,为什么不复用老的AOF文件?
  • AOF重写不复⽤AOF本⾝的⽇志,⼀个原因是⽗⼦进程写同⼀个⽂件必然会产⽣竞争问题,控制竞争就意味着会影响⽗进程的性能。
  • 如果AOF重写过程中失败了,那么原本的AOF⽂件相当于被污染了,⽆法做恢复使⽤。所以Redis AOF重写⼀个新⽂件,重写失败的话,直接删除这个⽂件就好了,不会对原先的AOF⽂件产⽣影响。等重写完成之后,直接替换旧⽂件即可。
 
内存快照—RDB
AOF记录的是操作命令,⽽不是实际的数据,所以,⽤AOF⽅法进⾏故障恢复的时候,需要逐⼀把操作⽇志都执⾏⼀遍。如果操作⽇志⾮常多,Redis就会恢复得很缓慢,影响到正常使⽤。
基于以上原因,redis有另外一套机制保持内存数据——内存快照
对Redis来说,它实现类似照⽚记录效果的⽅式,就是把某⼀时刻的状态以⽂件的形式写到磁盘上,也就是快照。这样⼀来,即使宕机,快照⽂件也不会丢失,数据的可靠性也就得到了保证。这个快照⽂件就称为RDB⽂件。
 
会阻塞主线程吗?
Redis提供了两个命令来⽣成RDB⽂件,分别是save和bgsave。
  • save:在主线程中执⾏,会导致阻塞;
  • bgsave:创建⼀个⼦进程,专⻔⽤于写⼊RDB⽂件,避免了主线程的阻塞,这也是Redis RDB⽂件⽣成的默认配置。
快照时数据能修改吗?
  • 如果快照执⾏期间数据不能被修改,是会有潜在问题的。在快照的Ns时间⾥,如果数据都不能被修改,Redis就不能处理对这些数据的写操作,那⽆疑就会给业务服务造成巨⼤的影响。
  • 如果使用bgsave命令,此时,主线程的确没有阻塞,可以正常接收请求,但是,为了保证快照完整性,它只能处理读操作,因为不能修改正在执⾏快照的数据。为了快照⽽暂停写操作,肯定是不能接受的。所以这个时候,Redis就会借助操作系统提供的写时复制技术(Copy-On-Write, COW)【当父线程操作一个已经存在的key时,会复制内存数据,另外开辟一块内存空间,当完成命令操作时,地址指向这个新的内存空间】,在执⾏快照的同时,正常处理写操作。
 
 
 
Redis 4.0中提出了⼀个混合使⽤AOF⽇志和内存快照的⽅法。简单来说,内存快照以⼀定的频率执⾏,在两次快照之间,使⽤AOF⽇志记录这期间的所有命令操作。这样⼀来,快照不⽤很频繁地执⾏,这就避免了频繁fork对主线程的影响。⽽且,AOF⽇志也只⽤记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现⽂件过⼤的情况了,也可以避免重写开销。
 

宕机了,Redis如何避免数据丢失?的更多相关文章

  1. Redis宕机的问题

    在主从模式下宕机要分为区分来看: slave从redis宕机 ​ 在Redis中从库重新启动后会自动加入到主从架构中,自动完成同步数据: ​ 如果从数据库实现了持久化,只要重新假如到主从架构中会实现增 ...

  2. [转帖]Redis持久化--Redis宕机或者出现意外删库导致数据丢失--解决方案

    Redis持久化--Redis宕机或者出现意外删库导致数据丢失--解决方案 https://www.cnblogs.com/xlecho/p/11834011.html echo编辑整理,欢迎转载,转 ...

  3. 04 AOF日志:宕机了,Redis如何避免数据丢失

    接下来两篇将记录Redis持久化存储两大技术:AOF日志.RDB快照 本篇重点 "AOF日志实现""AOF日志三种写回策略""AOF重写--避免日志过 ...

  4. Redis的KEYS命令引起宕机事件

    摘要: 使用 Redis 的开发者必看,吸取教训啊! 原文:Redis 的 KEYS 命令引起 RDS 数据库雪崩,RDS 发生两次宕机,造成几百万的资金损失 作者:陈浩翔 Fundebug经授权转载 ...

  5. redis集群节点宕机

    redis集群是有很多个redis一起工作,那么就需要这个集群不是那么容易挂掉,所以呢,理论上就应该给集群中的每个节点至少一个备用的redis服务.这个备用的redis称为从节点(slave). 1. ...

  6. redis宕机如何解决?如果是项目上线的宕机呢?

    我们先来了解一下  bridge网络模式 他会创建一个docker0桥,看完这个我们就会知道redis哨兵机制的端口了. 之后继续研究redis宕机的解决办法! 宕机: 服务器停止服务 如果只有一台r ...

  7. 宕机了,Redis数据丢了怎么办?

    持续原创输出,点击上方蓝字关注我 目录 前言 什么是AOF? 三种写回策略 日志文件太大怎么办? AOF重写会阻塞主线程吗? AOF的缺点 总结 什么是RDB? 给哪些数据做快照? 快照时能够修改数据 ...

  8. Redis 日志篇:无畏宕机快速恢复的杀手锏

    特立独行是对的,融入圈子也是对的,重点是要想清楚自己向往怎样的生活,为此愿意付出怎样的代价. 我们通常将 Redis 作为缓存使用,提高读取响应性能,一旦 Redis 宕机,内存中的数据全部丢失,假如 ...

  9. 由Redis的hGetAll函数所引发的一次服务宕机事件

    昨晚通宵生产压测,终于算是将生产服务宕机的原因定位到了,心累.这篇博客,算作一个复盘和记录吧... 先来看看Redis的缓存淘汰算法思维导图: 说明:当实际占用的内存超过Redis配置的maxmemo ...

  10. linux 双Redis + keepalived 主从复制+宕机自主切换

    主要核心思想,如果master 和 salve 全部存活的情况,VIP就漂移到 master.读写都从master操作,如果master宕机,VIP就会漂移到salve,并将之前的salve切换为ma ...

随机推荐

  1. Spring入门之IoC 的概念和作用(02)

    2.1 程序的耦合和解耦 2.1.1 程序的耦合耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量.耦合的强弱取决于模块间接口的复杂性.调用模块的方式以及通过界面传送数据的多少.模块间的 ...

  2. DevOps Gitlab环境部署

    DevOps 介绍 目录 DevOps 介绍 一.DevOps 介绍 1.1.1 DevOps 介绍 1.1.2 CI/CD简介 1.1.2 Gitlab安装与使用 一.DevOps 介绍 1.1.1 ...

  3. varchar(100)和varchar(10)的区别

    mysql存储字段"abcdef",varchar(10)和varchar(100)都可以存储,且占用的磁盘存储空间是一样的,磁盘是按照实际长度存储.但,如果需要排序等内存操作,加 ...

  4. AX2012 快速清空整个log表数据

    如果当一个log表的数据非常大的时又需要清理时,如果允许删除全部数据,在AX里,可以 将log表的TableType调整为[TempDB], 保存同步后再将TableType设置回[Regular]即 ...

  5. pyqt学习

  6. 【xUtils框架问题】xUtils继承基类的x.view().inject(this)绑定点击事件@Event无效

    由于看得教程里的xUtils比较老了,不知道什么版本的. 还是使用ViewUtils.inject()进行绑定反射的,使用@OnClick进行点击监听绑定的. 3.9.0版本的xUtils使用: x. ...

  7. Arduino教程目录

    目录 第一节.安装Arduino开发环境 第二节.第一个HelloWorld 第二节续.LED操作 呼吸灯 流水灯 正在加快制作,大家可以先看下面的视频了解基本语法,我准备基础课程和实际项目结合讲解. ...

  8. 什么是 SpringMvc

    SpringMvc 是 spring 的一个模块,基于 MVC 的一个框架,无需中间整合层来整合

  9. 1009.Django模型基础04

    一.数据库数据渲染到模板 二.案例的功能介绍 博客小案例功能介绍: 主页index.html--------------> 展示添加博客和博客列表的文字,实现页面跳转 添加页add.html-- ...

  10. [Cisco] Policy Based Routing

    在某些情況下,會希望指定特定的來源及目的走特定的出口,卻又不是全部的網段都希望套用,這時就可以透過PBR來達成這個需求. 如以下拓樸 1.1.1.0/24的網路往5.5.5.0的封包需要指定e0/1當 ...