Redis的数据时如何避免丢失的?

Redis之所以足够快,一部分的原因是它的数据都是基于内存存储的。虽然Redis更多的是作为一个旁路缓存【先在redis中查询,查询不到数据的时候,在查询持久化数据库】来使用。如果说服务器一旦宕机,内存中的数据就会全部丢失,即便是后端服务可以通过查询持久化数据库进行恢复,但是对于数据库来说压力会变大,从而有可能打崩数据库。这在业务高峰期是非常危险的,好在Redis提供了持久化机制,避免因为实例崩溃导致数据全部丢失。当然也正是Redis的持久化机制,在业务中也是存在直接将Redis缓存作为持久化数据库的。Redis提供了两种持久化机制,RDB快照以及AOF日志。

RDB内存快照

所谓的RDB(内存快照)就是把Redis内存中某一时刻的状态以文件的形式写到磁盘上,即:实现类似照片记录效果的方式。但是对于Redis用户来说有三个问题必须要探究:1.对什么数据做快照;2.快照期间是否会阻塞主线程,会阻塞多久;3.使用快照恢复数据要多久。

为了提供数据的可靠性保证,RDB执行的是全量快照,即将内存中所有的数据都转储为文件到磁盘上。由于是将内存数据转储为文件,所以需要对内存中的数据进行扫描,实例内存越大耗费的时间自然更多,转储到磁盘上的IO开销自然越大。

内存快照既然是内存再某一时刻的状态,即它反映的是内存在某一个时刻的事实数据,所以这个事实数据时不允许被改变的。既然快照期间内存数据不能被修改是不是意味着主线程会被阻塞?实际上并没有,Redis采用save和bgsave两个命令执行内存快照。save命令是在主线程中执行,会导致阻塞,直至快照完成;而bgsave是调用了操作系统提供的fork函数创建了一个子进程,专门用于写入RDB文件,bgsave也是Redis默认的配置。

fork操作是操作系统提供的一个内核API,redis在执行RDB或AOF重写时,会fork一个子线程去完成,并且使用CopyOnWrite的机制节约内存。但是fork出一个子线程的时候需要拷贝一个线程所必要的数据结构以及页表(虚拟内存与物理内存的映射)这个操作主线程必然是阻塞的。相对来说线程的数据结构是相对固定的,但是页表是和实例的内存大小相关的,实例内存越大,拷贝的页表的耗时也自然更大,延时自然更长。
所以从快照期间Redis的主线程其实是会被阻塞的。如果是采用save命令执行,主线程的阻塞将会持续到快照结束;而如果采用的是bgsave命令完成,主线程的阻塞将会发生在fork调用的期间,阻塞的时长主要取决于实例所占用的内存大小。此外,有一个不得不注意的是如果对redis的主线程进行了核绑,由于fork出的子线程会继承父线程的核绑特性,所以父子线程会出现争用CPU的情况。此时,快照耗时将会大大延长,还不如直接使用save命令完成。因此在生产环境中,将redis的线程进行核绑的明令禁止的。

庆幸的是,RDB文件是一个特殊的二进制紧凑压缩文件,在使用它用来恢复数据速度会比较快。这里的快其实是相对于使用AOF文件恢复相同的数据量的情况下而言的,当然也只有在这个前提下比较才会有意义。

尽管RDB可以解决Redis的数据宕机恢复问题,但是对于多久执行一次快照是一个令人纠结的地方。如果间隔时间过长,那么一次宕机所丢失的数据就越多,但是间隔时间太小,虽然丢失的数据少了,但是对于CPU和磁盘的开销就更大了,尤其是在生产环境中基本上单个节点就是上百G的内存数据。基于此Redis提供了另外一种持久化方式AOF解决实时数据的持久化。

AOF日志

Redis提供了AOF(append only file)持久化方式解决实时持久化的问题。AOF以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令达到恢复数据的目的。开启AOF功能需要设置配置: appendonly yes,默认不开启。 AOF文件名通过appendfilename配置设置,默认文件名是appendonly.aof。 保存路径同RDB持久化方式一致,通过dir配置指定。同样对于Redis用户来说有三个问题必须要探究:1.对什么数据做日志记录;2.实时日志持久化磁盘会不会阻塞主线程或是降低主线程的执行效率;3.AOF文件过大怎么办;4.使用AOF恢复数据需要多久。

Redis的AOF机制只会针对写命令生效,并且是写后日志,即先执行命令,把数据写入内存,然后才记录日志。此外有一点需要注意的是,这里说的写命令在日志里边其实是已经根据RESP协议解析后的写命令,而并未原生的命令,而且对于有过期时间的key,会统一将过期时间修改为绝对时间。

AOF的同步机制(为什么需要同步看最后)目前是有3个:
1.always:每次写入都要同步AOF文件,IO极为频繁,效率极低【看到某些博文说是由这个机制是由主线程完成,不确定,但自我猜测是必然的】
2.erverysec: 每秒同步是建议的同步策略, 也是默认配置, 做到兼顾性能和数据安全性。 理论上只有在系统突然宕机的情况下丢失1秒的数据(实际为不超过2秒的数据),这个同步操作是由其他线程发起所以不会阻塞主线程。
3.no:将文件的刷盘同步交由操作系统完成,所以同步周期不可控,性能是最好的,但是数据的可靠性无法保证。

Redis的数据时如何避免丢失的?

如果Redis长时间采用AOF记录实时写日志,那么必然导致AOF文件的过大。如果是并发写命令足够高的业务,一天就足以达到几个G,甚至几十G都是可能的。如果AOF文件过大其实有比较多的问题:1.文件大小本身受到文件系统的限制;2.存储成本以及备份所需要的时间更多;3.最重要的是使用AOF文件恢复时会更慢。所以Redis提供了AOF的重写机制。所谓的重写机制即是将多个命令合并为一个命令,因为在恢复数据的时候,我们关心的是最终的状态,而非过程。

那么AOF的重写日志什么时候会触发呢?Redis提供了bgrewriteaof命令来进行手动触发重写;并且提供了auto-aof-rewrite-min-size和auto-aof-rewrite-percentage配置自动触发重写,重写也是使用bgrewriteaof来完成的。

从图中可以看到bgrewriteaof的操作本身也是通过fork子线程来完成的,对主线程是会产生阻塞的。当fork操作完成之后,主线程仍旧可以继续执行读写命令,如果期间又有写命令执行的时候,这部分的增量日志如何处理呢?其实,这部分增量日志首先会被写入到AOF的重写缓冲池里,当AOF文件重写完成后会被同步到该文件中。

AOF文件恢复数据时时通过重放日志的方式来完成的,所以文件越大,恢复的时间就越长,对比内存快照而言,是非常慢的。

AOF+RDB的结合

从上述中可以看出RDB的优点是全量复制,数据恢复快,但是耗费的CPU以及IO成本较高,宕机后丢失的数据也较多;AOF的优点是实时记录,宕机丢失数据定格在2秒内,但是其恢复速度较慢,适用于做增量日志。因此Redis提供了aof-use-rdb-preamble yes配置将RDB以及AOF同时开启作为持久化。

在重启Redis时,先加载RDB快照,然后在重放AOF日志,完成数据的恢复,大幅度提升Redis的重启效率。

备注: 为什么用户程序将向文件写完之后还需要操作系统进行同步?
为了提高文件的写入效率,在现代操作系统中,当用户调用write函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满、或者超过了指定的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。如果同步文件之前, 如果此时系统故障宕机, 缓冲区内数据将丢失。为此,系统提供了fsync和fdatasync两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性。

参考资料:

极客时间专栏课-Redis核心技术与实战
<

Original: https://www.cnblogs.com/zhenjungan/p/16496349.html
Author: zhenjungan
Title: Redis的数据时如何避免丢失的?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/581878/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Linux命令

    Linux命令是对Linux系统进行管理的命令,对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核…

    Linux 2023年5月27日
    093
  • Git详细使用流程

    初始化git仓库 git init 执行命令后文件夹下将会在执行命令路径下生成.git隐藏文件上传该路径下的所有内容到暂存区 git add . 通常项目中都有read.me,创建…

    Linux 2023年6月7日
    0110
  • 【原创】Linux虚拟化KVM-Qemu分析(五)之内存虚拟化

    背景 Read the fucking source code! –By 鲁迅 A picture is worth a thousand words. –…

    Linux 2023年6月8日
    075
  • 一文带你掌握Spring Web异常处理方式

    一、前言 最近从单位离职了,离开了五年多来朝朝夕夕皆灯火辉煌的某网,激情也好悲凉也罢,觥筹场上屡屡物是人非,调转过事业部以为能换种情绪,岂料和下了周五的班的前同事兼好朋友,匆匆赶往…

    Linux 2023年6月6日
    091
  • Linux嵌套目录权限的比较探究

    在/tmp目录下新建一个嵌套目录,名字分别为test_0、test_1、test_2。在test_2目录下新建普通文件,名为tryme。设置test_0和test_2的权限为777…

    Linux 2023年6月7日
    086
  • redis的 分布式锁 golang/erlang 简单实现

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% import (% “redigo/redis”% ) %…

    Linux 2023年5月28日
    0113
  • JavaScript快速入门-02-基本语法

    2 基本语法 2.1 JavaScript简介 JavaScript 是一门 解释型语言,其代码在客户端中执行前不需经过编译,而是直接由浏览器解释执行。主要用作 客户端脚本语言,在…

    Linux 2023年6月7日
    0110
  • Linux通过手机USB网络共享上网

    多数情况下,服务器无法直接联网,需通过手机连线上网。设置方法如下: 终端中查看现有网络接口: ip addr 或 ifconfig 连接好数据线并在手机设置中打开”通过…

    Linux 2023年6月14日
    093
  • [Linux]iptables防火墙

    一、iptables介绍 二、表(Table) 三、链(Chain) 四、规则(Rule) 五、iptables规则的增删改查 一、iptables介绍 iptables是一个针对…

    Linux 2023年6月13日
    0109
  • Linux文件属性详述

    一、文件属性信息概述 文件属性信息组成如下: 文件索引属性信息——inode编号; 文件类型权限信息; 文件链接属性信息——硬链接数; 文件属主信息——文件所有者; 文件属组属性信…

    Linux 2023年5月27日
    0101
  • Linux-系统启动与MBR扇区修复

    1.系统启动过程 1.1 MBR扇区 1.2 MBR扇区的备份与还原 1.3 修复MBR 1.3.1 dd备份MBR信息 1.3.2 光驱启动修复 1.4 grub故障修复 1.系…

    Linux 2023年5月27日
    0130
  • 脚本安装lamp

    脚本安装lamp [root@localhost ~]# mkdir lamp [root@localhost ~]# cd lamp/ [root@localhost lamp]…

    Linux 2023年6月6日
    0126
  • Linux动静分离与Rewrite

    一、动静分离 1.1 单台机器动静分离 1、创建NFS挂载点(NFS服务端) mkdir /static vim /etc/exports /static 172.16.1.0/2…

    Linux 2023年6月14日
    087
  • 聊聊Netty那些事儿之从内核角度看IO模型

    从今天开始我们来聊聊Netty的那些事儿,我们都知道Netty是一个高性能异步事件驱动的网络框架。 它的设计异常优雅简洁,扩展性高,稳定性强。拥有非常详细完整的用户文档。 同时内置…

    Linux 2023年6月6日
    085
  • ArchLinux安装-2022-01-12

    这篇教程,是我基于B站up住theCW的视频教程整理的,其中添加了一些我在安装n次之后的经验(虽然失败过几次,但我现在安装不会再出差错,所以请放心的看此教程) 当然,我认为theC…

    Linux 2023年6月13日
    098
  • 操作系统实现-loader

    博客网址:www.shicoder.top微信:18223081347欢迎加群聊天 :452380935 大家好呀,终于我们到了操作系统的loader部分了,loader也是操作系…

    Linux 2023年6月13日
    072
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球