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)

大家都在看

  • Springboot 的一些默认配置规则

    本文样例说明仅适用 maven 环境和语法,但所述内容也适用 gradle 1. logback 日志默认为 slf4j + logback 框架,引入如下 jar 之后,就自动引…

    Linux 2023年6月6日
    079
  • vsftpd 操作手册-完整版

    vsftpd 目录 – ftp 简介 – vsftpd 简介 – vsftpd 安装&卸载 – vsftpd 配置文件 – vsftpd 认证模板 – vsftpd 配置模…

    Linux 2023年6月13日
    075
  • Postman 正确使用姿势

    前言: 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i 简介: Postman是一个接口测试工具,在做接口测试的时候,Postman相当于一个客户端,它可以模拟用户发起的…

    Linux 2023年6月14日
    067
  • JavaScript this

    本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。 博主的文章没有高度、深度和广度,只是凑字数。由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。 博主…

    Linux 2023年6月13日
    080
  • CenterOS对防火墙和端口号的操作

    1 防火墙设置 (1)设置开机启用防火墙:systemctl enable firewalld.service (2)设置开机禁用防火墙:systemctl disable fir…

    Linux 2023年6月7日
    079
  • ORA-01950: no privileges on tablespace ‘USERS’– 解决办法

    ORA-01950: no privileges on tablespace ‘USERS’ 原因: 在表空间 “USERS” 无权…

    Linux 2023年6月6日
    0339
  • 我们做了一个操作系统,不是Windows,也不是Linux

    这是一个操作系统,有和Windows一样的桌面,通过鼠标和键盘使用图形界面,但是不是Windows。 也有和Linux一样的终端,通过输入字符命令,即能处理本地的工作,还能远程操控…

    Linux 2023年6月6日
    074
  • go——数组

    GO——数组 一、一维数组声明方式: 1. var 数组名 [数组长度] 数组类型 var arr [5]int //定义一个数组,有5个元素,数组类型为整形 2.var 数组名=…

    Linux 2023年6月7日
    098
  • Git基本使用命令

    Git配置 Git最小配置 配置全局账户,该账户对所有Git仓库都有效 git config –global user.name ‘&#x8D26;&#x6237…

    Linux 2023年6月13日
    070
  • linux系统编码修改

    查看当前系统默认采用的字符集locale 查看系统当前编码echo $LANG如果输出为:en_US.UTF-8 英文zh_CN.UTF-8 中文 查看系统是否安装中文字符集loc…

    Linux 2023年6月6日
    086
  • Redis无法向磁盘写入RBD数据

    由于客户为了安全规范,规定Redis不能再root权限下运行,所以要进行降权切成普通用户等操作,刚刚做完切权操作。客户监控发出来项目服务的报错邮件,经过查看发现是Redis问题. …

    Linux 2023年6月8日
    0104
  • 微信聊天内容可以被监听吗

    上班摸鱼与网络安全 成为了锅叔在博客园阅读数最高的一篇文章,足可见同学们上班摸鱼的热情,同时也反映了大家对网络安全的担忧…… 对于其中的一个存疑问题,&#8…

    Linux 2023年6月13日
    090
  • Netty-如何写一个Http服务器

    前言 动机 最近在学习Netty框架,发现Netty是支持Http协议的。加上以前看过Spring-MVC的源码,就想着二者能不能结合一下,整一个简易的web框架(PS:其实不是整…

    Linux 2023年6月7日
    090
  • [ Shell ] 通过 Shell 脚本导出 CDL 网表

    通过 si 导出电路网表,实际上在 Virtuoso 中通过菜单 File – Export – CDL 和 Calibre LVS 中 Export fr…

    Linux 2023年6月7日
    0136
  • centos7 设置开机启动任务

    环境:centos7 需求:前两天调通的DNS server(bind/named)设置开机自启动 操作: 修改 /etc/rc.local 注意这个 rc.local 文件默认是…

    Linux 2023年6月6日
    093
  • PTA 《基础编程题目集》 6-6 求单链表结点的阶乘和

    本题要求实现一个函数,求单链表L结点的阶乘和。这里默认所有结点的值非负,且题目保证结果在int范围内。 函数接口定义: int FactorialSum( List L ); 其中…

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