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)

大家都在看

  • python操作MySQL;MySQL补充知识

    目录 1.python操作MySQL 2.SQL注入及解决方式 3.二次确认 4.修改表SQL语句补充 5.视图 6.触发器 7.事务 8.存储过程 9.函数 10.流程控制 11…

    Linux 2023年6月7日
    0107
  • 02-MySQL关键字、Select语句执行顺序

    SQL关键字 1、分页 MySQL的分页关键词是 limit SELECT * FROM student LIMIT 2,6:查询学生表中的数据,从第三条开始,显示6条数据 2、分…

    Linux 2023年6月7日
    085
  • go-切片的追加

    // The append built-in function appends elements to the end of a slice. If // it has suffi…

    Linux 2023年6月13日
    077
  • 【Javaweb】JSP标准标签库

    JSTL 1.什么是JSTL 2.版本 3.标签函数库 4.优点 JSTL基本概念 标签(Tag) 标签库(Tag library) 标签库描述文件(Tag Library Des…

    Linux 2023年6月14日
    0155
  • Linux之export命令

    镜像下载、域名解析、时间同步请点击阿里云开源镜像站 export命令用于将shell变量输出为环境变量,或者将shell函数输出为环境变量。 一个变量创建时,它不会自动地为在它之后…

    Linux 2023年5月27日
    0121
  • 剑指offer计划27(栈与队列困难)—java

    1.1、题目1 剑指 Offer 59 – I. 滑动窗口的最大值 1.2、解法 解题思路:(来自作者bigbeats) 相当于维护一个最大队列(队头元素最大,向队尾非…

    Linux 2023年6月11日
    083
  • bash 教程-4 shell 脚本 调试 环境 [MD]

    我的GitHub 我的博客 我的微信 我的邮箱 bqt20094 baiqiantao@sina.com 脚本基础 脚本 script 就是包含一系列命令的一个文本文件,所有能够在…

    Linux 2023年5月28日
    090
  • linux-查看公钥的指纹值或者部署密钥的指纹值

    背景 查看gitlab上面的[部署密钥],看到了指纹 [xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx],怎么知道这个部署密钥的指纹…

    Linux 2023年6月6日
    0108
  • MySQL-连接数据库

    连接数据库在操作数据库之前,需要连接它,输入命令:mysql -u用户名 -p密码。 在你自己本机上连接数据库用上述方式是可以的,不过在平台上连接数据库还需要加上一句-h127.0…

    Linux 2023年6月8日
    097
  • 高级IPC DBus

    404. 抱歉,您访问的资源不存在。 可能是URL不正确,或者对应的内容已经被删除,或者处于隐私状态。 [En] It may be that the URL is incorre…

    Linux 2023年5月27日
    0106
  • 剑指offer计划21( 位运算简单)—java

    1.1、题目1 剑指 Offer 15. 二进制中1的个数 1.2、解法 通过判断每一位的与来识别1的数量。 1.3、代码 public class Solution { // y…

    Linux 2023年6月11日
    0133
  • NoteOfMySQL-12-备份与还原

    一、备份概述 备份不是单纯的复制数据,因为这样无法留下历史记录和系统的DNS或Registry等信息。完整的备份应包括自动化的数据管理与系统的全面恢复,即备份=复制+管理。 1. …

    Linux 2023年6月14日
    075
  • 【Linux进程间通信】共享内存的使用

    背景 最近需要开发一个测试程序,接受Tester端的测试指令,执行一条条外设的测试用例,执行完成后将测试数据的结果上报,上报方式未定,考虑到耦合和配套问题,决定采用共享内存机制,设…

    Linux 2023年6月13日
    0102
  • shell handle

    !/bin/bash qinrui set -e commitId =” repoPath =” x1 =” if [-f changes15….

    Linux 2023年5月28日
    0107
  • Ubuntu14.04.5升级openssh8.0p1版本

    一、前言客户请广电公司扫描服务器漏洞,扫到阿里云服务器的OpenSSH_6.6.1p1版本存在如下高危漏洞,基于安全的考量,升级到8.0版本。1.OpenSSH安全绕过漏洞2.Op…

    Linux 2023年6月8日
    090
  • 通过示例学习PYTORCH

    核心是:PyTorch提供了两个主要的特性: 一个n维的Tensor,与Numpy相似但可以在GPU上运行 构建和训练神经网络的自动微分 我们将使用一个三阶多项式拟合 (y=sin…

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