一文带你搞懂Redis持久化

Redis持久化

Redis的数据是存储在内存的,当程序崩溃或者服务器宕机,那么内存里的数据就会丢失。所以避免数据丢失的情况,需要将数据保存到其他的存储设备中。

Redis提供两种方式来持久化,分别是

  • RDB(Redis Database):记录某个时刻的全部数据,本质是存储二进制数据的快照到磁盘,后续通过加载RDB文件恢复数据

  • AOF(Append Only File):记录执行的每条命令,通过重新执行命令来恢复数据。本质是记录操作日志,后续通过日志恢复数据。

RDB

本质

记录某个时刻的全部数据,本质是:将某一时刻Redis服务器内存中的数据保存到磁盘中的二进制文件中(dump.rdb),后续通过加载RDB文件恢复数据。

RDB触发(执行持久化)

RDB的触发包括手动触发,自动触发,关闭时持久化

  1. 手动触发包括主动执行sava命令,主动执行bgsave命令:

  • save命令:会在redis主线程执行持久化操作,会阻塞主线程,只有RDB持久化完成,才能响应客户端的请求,所以在生产模式的时候慎用(不用)。Redis在正常关闭时,会执行save命令来持久化数据

  • bgsave命令:background save,即后台保存。Redis会创建一个子进程来生成快照文件,创建子进程可能会有短暂的阻塞,而父进程(Redis的服务器进程)会继续处理客户端的请求。一般用的是这个命令

  1. 自动触发:

用户可以在Redis的配置文件中进行设置(默认开启),Redis会根据设置自动调用bgsave。比如,

#save <seconds> <changes>
save 900 1 表示每900秒内,有1条写数据操作,则触发bgsave
save 300 10 多条命令是并集关系,如果满足其中一个就会触发
RDB执行流程

Redis官网描述:

How it works
Whenever Redis needs to dump the dataset to disk, this is what happens:
1.Redis forks. We now have a child and a parent process.
2.The child starts to write the dataset to a temporary RDB file.
3.When the child is done writing the new RDB file, it replaces the old one.
This method allows Redis to benefit from copy-on-write semantics.
  1. Redis fork出一个子进程

  2. 子进程把数据写入临时的RDB文件

  3. 写完之,新RDB文件替换旧RDB文件

最后还有一句话:这种方式让Redis从”写时复制“技术收益。也就是,Redis在执行持久化的时候,依然可以处理客户端的命令,数据是可以被修改的。

具体来讲,fork创建子进程后,子进程会复制父进程的页表,页表指向的物理地址是同一个,所以子进程和父进程时共享同一片数据的。当父进程处理客户端请求,发生内存数据修改时,物理内存才会被复制一份给子进程,所以子进程的持久化操作是不会被影响。

AOF

记录执行的每条命令,通过执行命令来恢复数据。本质是记录操作日志,后续通过日志恢复数据。

AOF日志文件其实就是普通的文本,可以通过cat命令查看里面的内容。

Redis先执行写操作命令后,再将该命令记录到AOF日志中。有以下几点好处:

  1. 避免额外的检查开销。如果命令的语法有问题又不进行检查,直接先记录到AOF日志里,等到Redis使用日志文件恢复数据的时候,就会出错。所以先执行命令后,只有命令执行成功才记录到AOF日志中,就能避免额外的检查开销,保证AOF日志里的命令是正确的。

  2. 不会阻塞当前操作命令的执行。

当然也存在一定风险:

  1. 执行写操作和记录AOF日志是两个过程,当Redis还没有来得及将命令写入硬盘时,服务器宕机,数据就有丢失的风险

  2. 会阻塞下一个操作命令的执行。

因为执行命令和记录AOF日志都是在主进程完成的

开启AOF

打开redis配置文件

appendonly no
​
# The name of the append only file (default: "appendonly.aof")
​
appendfilename "appendonly.aof"

默认AOF是关闭的,通过设置appendonly为yes可开启

AOF写入流程
  1. 将数据写入AOF缓冲区中,这个缓冲区叫aof_buf,是一个sds数据

  2. 将aof_buf的数据写入AOF文件,此时还没有写入硬盘,而是拷贝到内核缓冲区page cache中。一共有4个时机,会调用一个flushAppendOnlyFile的函数,这个函数会使用write函数来将数据写入操作系统缓冲区

    1. 处理完事件后,等待下一次事件之前,也就是beforeSleep中

    2. 周期函数serverCron中

    3. 服务器退出之前的准备工作时

    4. 通过配置指令关闭AOF功能时

    内核缓冲区page cache:是操作系统内核中用于缓存磁盘数据的一部分内存区域

    硬盘缓冲区:是硬盘或磁盘控制器中的硬件缓存

  3. 将内核缓冲区的数据写入磁盘。即调用系统的flush函数,刷盘其实还是在flushAppendOnlyFile函数中,但是不一定调用了flushApeendOnlyFile,flush就一定会被调用。这里支持了刷盘时机的配置。

    /* Perform the fsync if needed. */
    if (server.aof_fsync == AOF_FSYNC_ALWAYS) {/* redis_fsync is defined as fdatasync() for Linux in order to avoid* flushing metadata. */latencyStartMonitor(latency);redis_fsync(server.aof_fd); /* Let's try to get this data on the disk */latencyEndMonitor(latency);latencyAddSampleIfNeeded("aof-fsync-always",latency);server.aof_last_fsync = server.unixtime;
    } else if ((server.aof_fsync == AOF_FSYNC_EVERYSEC &&server.unixtime > server.aof_last_fsync)) {if (!sync_in_progress) aof_background_fsync(server.aof_fd);server.aof_last_fsync = server.unixtime;
    }

注意:

  1. 为什么先将数据写入aof缓冲中,而不直接同步到磁盘呢?

    因为实时写入磁盘会带来很高的磁盘IO,影响性能

AOF写入策略(AOF日志写入磁盘时机)

Redis提供了三种写入策略,决定了AOF日志什么时候写入磁盘,包括

  • appendfsync always:每次写操作命令执行完之后,同步将AOF日志数据写入磁盘。

  • appendfsync everysec:每次写操作命令执行完之后,先将命令写入到AOF文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写入磁盘

  • appendfsync no:Redis不去控制写入硬盘的时机,由操作系统控制。每次先将命令写入AOF文件的内核缓冲区,再由操作系统决定何时写入硬盘。一般情况linux会每30秒刷一次盘。这种策略对性能的影响最小,但发生崩溃时会丢失较多数据。

Redis的默认设置是每秒钟同步一次数据到磁盘,提供较好的性能和数据可靠性。也需要根据实际业务来选择,比如只是简单的缓存,不存在热点缓存,就可以30秒同步一次数据到磁盘中。Always策略每次执行写操作就同步将AOF日志写入硬盘,影响主进程的性能。

根据业务场景进行选择:

  • 如果要高性能,就选No策略

  • 如果要高可靠,就选Always策略

  • 如果折中,较好的性能和可靠性,就选Everysec策略

AOF重写

随着命令越来越多,AOF文件会越来越大,不仅占用大量磁盘空间,而且恢复数据也会变慢。

在AOF文件中,有些命令是没有作用的,比如一开始set一个数据为10,后来又set为100,那么前面set为10就没有作用了,完全可以把前面set为10的命令去掉。

所以,AOF重写机制的妙处在于,尽管某个键值对被多条命令重复修改,最终也只需用一条命令去记录这个键值对当前的最新状态,进而减少AOF日志中的命令数量。

AOF重写流程

写入AOF日志的操作是在主进程完成的,因为它写入的内容不多,所以不太影响命令的操作。

而AOF重写时,需要读取所有缓存的键值对数据,为每一个键值对生成一条命令,然后写入到新的AOF文件,重写完后,将旧AOF文件替换掉。所以AOF过程由后台子进程来完成,避免阻塞主进程。

这里使用子进程而不是线程,因为如果是使用线程,多线程之间会共享内存,那么在修改共享内存数据的时候,需要通过加锁来保证数据的安全,而这样就会降低性能。而使用子进程,创建子进程时,父子进程是共享内存数据的,不过这个共享的内存只能以只读的方式,而当父子进程任意一方修改了该共享内存,就会发生「写时复制」,于是父子进程就有了独立的数据副本,就不用加锁来保证数据安全。

  1. 重写时,主进程会fork出一个子进程,由子进程将这些Redis数据写入重写日志

  2. 在子进程进行重写期间,主进程也会将新的写操作写入到AOF重写缓冲区中

  3. 当新的AOF文件创建完毕,Redis就会将重写缓冲区的内容追加到新的AOF文件,新AOF文件替换旧AOF文件

所以,尽管重写过程中有新数据写入,通过追加AOF重写缓冲的方式到新文件,依然可以保证不会丢失最新的写入操作

AOF混合持久化

是什么

混合持久化发生在原有的AOF流程。开启了混合持久化,在AOF重写日志的时候,fork出来的子进程会将内存数据以RDB的方式写入新的AOF文件中,期间主进程将写操作命令写入重写缓冲区中,最后追加到新的AOF文件中。

此时的AOF文件前半部分是RDB格式的全量数据,后半部分是AOF格式的增量数据。

优势

既有RDB文件小,加载快的优势,也有AOF持久化数据损失少的优势。但因为含有二进制数据,可读性会差一些。

服务启动时如何加载数据

混合持久文件里有REDIS这个标记,加载时能通过这个标记进行判断是否开启了混合持久化。

可以通过配置文件开启,5.0之后默认是打开的,所以5.0之后只要AOF配置开启,默认就是混合持久化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/145710.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode热题100】--19.删除链表的倒数第N个结点

19.删除链表的倒数第N个结点 注意&#xff1a;先声明一个头结点&#xff0c;它的next指针指向链表的头节点&#xff0c;这样就不需要对头节点进行特殊的判断 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListN…

【Java每日一题】——第十六题:将数组元素逆序并遍历输出。(2023.09.30)

&#x1f578;️Hollow&#xff0c;各位小伙伴&#xff0c;今天我们要做的是第十五题。 &#x1f3af;问题&#xff1a; 设有数组如下&#xff1a;int[] arr{11,34,47,19,5,87,63,88}; 测试结果如下&#xff1a; &#x1f3af; 答案&#xff1a; int a[]new int [10];Random …

华为云HECS云服务器docker环境下安装nginx

前提&#xff1a;有一台华为云服务器。 华为云HECS云服务器&#xff0c;安装docker环境&#xff0c;查看如下文章。 华为云HECS安装docker-CSDN博客 一、拉取镜像 下载最新版Nginx镜像 (其实此命令就等同于 : docker pull nginx:latest ) docker pull nginx查看镜像 dock…

ai创作工具,怎么使用AI创作工具

不论是写一篇博客、发布自媒体、还是设计广告文案&#xff0c;创作都成为了我们日常生活和工作中不可或缺的一部分。但是&#xff0c;许多人可能会面临写作灵感枯竭、时间不足或需要大量内容的问题。 写作对于很多人来说&#xff0c;不仅是一项技能&#xff0c;更是一种挑战。有…

Spring学习笔记11 GoF代理模式

Spring学习笔记10 JdbcTemplate_biubiubiu0706的博客-CSDN博客 新建个maven模块 static-proxy 演示静态代理 订单接口 测试 需求:统计每个业务方法的耗时 package com.example.proxy.service;/*** author hrui* date 2023/9/25 8:42*/ public class OrderServiceImpl implem…

Linux CentOS7 vim临时文件

在vim中&#xff0c;由于断网、停电、故意退出、不小心关闭终端等多种原因&#xff0c;正在编辑的文件没有保存&#xff0c;系统将会为文件保存一个交换文件&#xff0c;或称临时文件&#xff0c;或备份文件。 如果因某种原因产生了交换文件&#xff0c;每次打开文件时&#x…

ffmpeg、ffplay在线安装,离线导出整个程序,移植到其他服务器使用(linux系统)

环境说明 以ubuntu系统作为说明 在线安装 下面命令会同时安装ffplay和ffmpeg sudo apt-get install ffmpeg怎么验证安装成功&#xff1f; 输入ffmpeg命令 ffmpeg&#xff0c;如图则说明安装成功 转储可执行程序和依赖的文件 找到安装路径&#xff0c;一般在/usr/bin目录…

idea Springboot 教师标识管理系统开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 教师标识管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统 具有完整的源代码和数据库&…

Codeforces Round 894 (Div. 3) D(数学题好难不会)

题目链接&#xff1a;Codeforces Round 894 (Div. 3) D 题目&#xff1a; 特马决定提高自己制作冰淇淋的技能。他已经学会了如何用两个球把冰淇淋做成圆锥形。 在痴迷冰淇淋之前&#xff0c;特马对数学很感兴趣。因此&#xff0c;他很想知道要制作完全n个不同类型的冰淇淋&am…

唤醒手腕 2023年 B 站课程 Golang 语言详细教程笔记(更新中)

0001、1000集GO语言Flag毒誓 唤醒手腕UP猪Pig目标花费1000集进行讲解Go语言视频学习教程&#xff08;有趣的灵魂&#xff0c;适合小白&#xff0c;不适合巨佬&#xff09;&#xff0c;从2023年3月19日开始&#xff0c;将会一直每天更新&#xff0c;准备在2024年5月1日之前更新…

【C语言】文件操作(二)

前言&#xff1a; 在文件操作&#xff08;一&#xff09;中我们了解了文件及文件指针&#xff0c;还有文件的打开和关闭。在这篇博客我们学习顺序读写文件的几个函数。 文章目录 一、文件的顺序读写1.1 顺序读写函数介绍 fgetc 字符输入函数 fputc 字符输出函数fgets 文本行输…

Android studio升级Giraffe | 2022.3.1 Patch 1踩坑

这里写自定义目录标题 not "opens java.io" to unnamed module错误报错信息解决 superclass access check failed: class butterknife.compiler.ButterKnifeProcessor$RScanner报错报错信息解决 Android studio升级Giraffe | 2022.3.1 Patch 1后&#xff0c;出现项目…

web:[极客大挑战 2019]PHP

题目 点进页面显示如下 根据页面提示&#xff0c;这个网站有备份文件&#xff0c;备份文件一般是bak文件格式&#xff0c;用dirsearch扫描 访问之后下载了一个文件 里面都是一些代码 在index.php中发现了一个类的文件&#xff0c;一个get传参&#xff0c;然后将传进的值进行反序…

【数据结构】树的概念理解和性质推导(保姆级详解,小白必看系列)

目录 一、前言 &#x1f34e; 为什么要学习非线性结构 ---- 树&#xff08;Tree&#xff09; &#x1f4a6; 线性结构的优缺点 &#x1f4a6; 优化方案 ----- 树&#xff08;Tree&#xff09; &#x1f4a6; 树的讲解流程 二、树的概念及结构 &#x1f350; 树的概念 &…

QCefView 简介

什么是QCefView QCefView 是为 Qt 开发的一个封装集成了CEF(Chromium Embedded Framework)库的Wdiget UI组件。使用QCefView可以充分发挥CEF丰富强大的Web能力&#xff0c;快速开发混合架构的应用程序。它不需要开发者理解CEF的细节&#xff0c;能够在Qt中更容易的使用CEF&…

NLP 项目:维基百科文章爬虫和分类 - 语料库阅读器

塞巴斯蒂安 一、说明 自然语言处理是机器学习和人工智能的一个迷人领域。这篇博客文章启动了一个具体的 NLP 项目&#xff0c;涉及使用维基百科文章进行聚类、分类和知识提取。灵感和一般方法源自《Applied Text Analysis with Python》一书。 在接下来的文章中&#xff0c;我将…

Android 编译插桩操纵字节码

本文讲解如何编译插桩操纵字节码。 就使用 ASM 来实现简单的编译插桩效果&#xff0c;通过插桩实现在每一个 Activity 打开时输出相应的 log 日志。实现思路 过程主要包含两步&#xff1a; 1、遍历项目中所有的 .class 文件​ 如何找到项目中编译生成的所有 .class 文件&#…

初识多线程

一、多任务 现实中太多这样同时做多件事的例子了&#xff0c;例如一边吃饭一遍刷视频&#xff0c;看起来是多个任务都在做&#xff0c;其实本质上我们的大脑在同一时间依旧只做了一件事情。 二、普通方法调用和多线程 普通方法调用只有主线程一条执行路径 多线程多条执行路径…

xPortPendSVHandler任务切换流程

__asm void xPortPendSVHandler( void ) { extern uxCriticalNesting; extern pxCurrentTCB; extern vTaskSwitchContext; PRESERVE8 mrs r0, psp isb//指令同步命令&#xff0c; ldr r3, pxCurrentTCB /* Get the location of the current TCB. */ ldr r2, [r3]//r2保存…

【面试经典150 | 矩阵】螺旋矩阵

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;模拟方法二&#xff1a;按层模拟 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于…