宕机了, redis如何保证数据不丢?
前言
如果有人问你:"你会把 Redis 用在什么业务场景下?"
我想你大概率会说:"我会把它当作缓存使用,因为它把后端数据库中的数据存储在内存中,然后直接从内存中读取数据,响应速度会非常快。"
没错,这确实是 Redis 的一个普遍使用场景,但是,这里也有一个绝对不能忽略的问题:一旦服务器宕机,内存中的数据将全部丢失。
目前,Redis 的持久化主要有两大机制,即 AOF(Append Only File
)日志和 RDB(Redis DataBase
) 快照。
AOF
日志是如何实现的
说到日志,我们比较熟悉的是数据库的写前日志(Write Ahead Log, WAL
),在实际写数据前,先把修改的数据记到日志文件中,以便故障时进行恢复。不过,AOF 日志正好相反,它是写后日志,"写后"的意思是 Redis 是先执行命令,把数据写入内存,然后才记录日志。
AOF 里记录的是 Redis 收到的每一条命令,这些命令是以文本形式保存的。
我们以 Redis 收到“set testkey testvalue”命令后记录的日志为例,看看 AOF 日志的内容。其中,“*3”表示当前命令有三个部分,每部分都是由“$+数字”开头,后面紧跟着具体的命令、键或值。这里,“数字”表示这部分中的命令、键或值一共有多少字节。例如,“$3 set”表示这部分有 3 个字节,也就是“set”命令。
写后日志的优势与风险
为了避免额外的检查开销,Redis 在向 AOF 里面记录日志的时候,并不会先去对这些命令进行语法检查。
如果先记日志再执行命令的话,日志中就有可能记录了错误的命令,Redis 在使用日志恢复数据时,就可能会出错。而写后日志这种方式,就是先让系统执行命令,只有命令能执行成功,才会被记录到日志中,否则,系统就会直接向客户端报错。
所以,Redis 使用写后日志这一方式的一大好处是,可以避免出现记录错误命令的情况。
除此之外,写后日志一个好处:它是在命令执行后才记录日志,不会阻塞当前的写操作。
AOF 也有两个潜在的风险:
-
如果此时 Redis 是用作缓存,还可以从后端数据库重新读入数据进行恢复。
-
如果 Redis 是直接用作数据库的话,此时,因为命令没有记入日志,所以就无法用日志进行恢复了。
-
AOF 日志也是在主线程中执行(写回策略为 always 时),如果在把日志文件写入磁盘时,磁盘写压力大,就会导致写盘很慢,进而导致后续的操作也无法执行了。
-
风险一:如果刚执行完一个命令,还没有来得及记日志就宕机了,那么这个命令和相应的数据就有丢失的风险。
-
风险二:AOF 虽然避免了对当前命令的阻塞,但可能会给下一个操作带来阻塞风险。
这两个风险都是和 AOF 写回磁盘的时机相关的。这也就意味着,如果我们能够控制一个写命令执行完后 AOF 日志写回磁盘的时机,这两个风险就解除了。
日志的写回策略
AOF 机制一共有三种写回策略,也就是 AOF 配置项 appendfsync
的三个可选值。
-
Always 同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
-
Everysec 每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
-
No 操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
针对避免主线程阻塞和减少数据丢失问题,这三种写回策略都无法做到两全其美。
我们就可以根据系统对高性能和高可靠性的要求,来选择使用哪种写回策略了。
-
想要获得高性能,就选择 No 策略;
-
想要得到高可靠性保证,就选择 Always 策略;
-
允许数据有一点丢失,又希望性能别受太大影响的话,那么就选择 Everysec 策略。
日志的重写
重写的作用
AOF 是以文件的形式在记录接收到的所有写命令。随着接收的写命令越来越多,AOF 文件会越来越大。这也就意味着,我们一定要小心 AOF 文件过大带来的性能问题,主要在于以下三个方面:
-
一是,文件系统本身对文件大小有限制,无法保存过大的文件;
-
二是,如果文件太大,之后再往里面追加命令记录的话,效率也会变低;
-
三是,如果发生宕机,AOF 中记录的命令要一个个被重新执行,用于故障恢复,如果日志文件太大,整个恢复过程就会非常缓慢,这就会影响到 Redis 的正常使用。
AOF 重写机制就是在重写时,Redis 根据数据库的现状创建一个新的 AOF 文件,也就是说,读取数据库中的所有键值对,然后对每一个键值对用一条命令记录它的写入。重写机制具有“多变一”功能。所谓的“多变一”,也就是说,旧日志文件中的多条命令,在重写后的新日志中变成了一条命令。
重写的过程
AOF 日志由主线程写回不同,重写过程是由后台子进程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
我把重写的过程总结为“一个拷贝,两处日志”。
“一个拷贝”就是指,每次执行重写时,主线程 fork 出后台的 bgrewriteaof 子进程。此时,fork 会把主线程的内存拷贝一份给 bgrewriteaof 子进程,这里面就包含了数据库的最新数据。然后,bgrewriteaof 子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。
第一处日志,指的是因为主线程未阻塞,仍然可以处理新来的操作,Redis 会把这个操作写到它的缓冲区。这样一来,即使宕机了,这个 AOF 日志的操作仍然是齐全的,可以用于恢复。
第二处日志,就是指新的 AOF 重写日志。这个操作也会被写到重写日志的缓冲区。这样,重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。
此时,我们就可以用新的 AOF 文件替代旧文件了。
总结来说,每次 AOF 重写时,Redis 会先执行一个内存拷贝,用于重写;然后,使用两个日志保证在重写过程中,新写入的数据不会丢失。而且,因为 Redis 采用子进程进行日志重写,所以,这个过程并不会阻塞主线程。
正因为记录的是操作命令,而不是实际的数据,所以,用 AOF 方法进行故障恢复的时候,需要逐一把操作日志都执行一遍。如果操作日志非常多,Redis 就会恢复得很缓慢,影响到正常使用。这当然不是理想的结果。那么,还有没有既可以保证可靠性,还能在宕机时实现快速恢复的其他方法呢?
RDB
对 Redis 来说,它实现类似照片记录效果的方式,把某一时刻的状态以文件的形式写到磁盘上,也就是快照(RDB 文件)。这样一来,即使宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。
和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。
快照的原理
Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave。
-
save:在主线程中执行,会导致阻塞;
-
bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。
我们可以通过 bgsave 命令来执行全量快照,这既提供了数据的可靠性保证,也避免了对 Redis 的性能影响。
在执行快照的同时,Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW
),正常处理写操作。bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。
如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本(键值对 C’)。然后,主线程在这个数据副本上进行修改。同时,bgsave 子进程可以继续把原来的数据(键值对 C)写入 RDB 文件。
这样既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
混合 AOF/RDB
虽然 bgsave 执行时不阻塞主线程,但是,如果频繁地执行全量快照,也会带来两方面的开销。
一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环(所以,在 Redis 中如果有一个 bgsave 在运行,就不会再启动第二个 bgsave 子进程)。
另一方面,bgsave 子进程需要通过 fork 操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。
总结
最后,关于 AOF 和 RDB 的选择问题,我想再给你提三点建议:
-
数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;
-
如果允许分钟级别的数据丢失,可以只使用 RDB;
-
如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。
相关文章:

宕机了, redis如何保证数据不丢?
前言 如果有人问你:"你会把 Redis 用在什么业务场景下?" 我想你大概率会说:"我会把它当作缓存使用,因为它把后端数据库中的数据存储在内存中,然后直接从内存中读取数据,响应速度会非常快。…...

太速科技-基于XCVU9P+ C6678的100G光纤的加速卡
基于XCVU9P C6678的100G光纤的加速卡 一、板卡概述 二、技术指标 • 板卡为自定义结构,板卡大小332mmx260mm; • FPGA采用Xilinx Virtex UltralSCALE 系列芯片 XCVU9P; • FPGA挂载4组FMC HPC 连接器; • 板载4路QSPF,每路数据速…...

Maven:一个下载jar依赖失败的问题解决方案
内部的一个jar包已经上传到了私服上,在私服管理端也能看到该jar包的完整信息,但是springboot项目引入该jar包发现死活下载不下来,报错如图: 从该错误信息中可以看到,找不到服务名是xxl-job这个的,我们要找的…...
Java 枚举的基本使用
一、枚举的概述 java 枚举(Enum)是一种特殊的数据类型,它允许你定义一组命名的常量。在 Java 中,枚举被实现为类,并且继承自 java.lang.Enum 类。枚举的使用可以提供类型安全、可读性强、易于理解的代码。 (1) 枚举的…...
Semaphroe + CountDown
Semaphore 基本使用 synchronized 可以起到锁的作用,但某个时间段内,只能有一个线程允许执行 Semaphore(信号量)用来限制能同时访问共享资源的线程上限(不是资源数),非重入锁 不像之前的reen…...

解读代理 IP差异:ISP 代理与住宅代理
独立IP作为跨境必备工具,代理类型五花八门,今天IPFoxy全球代理将为搭建科普:ISP代理与住宅代理在理论上与使用上的区别。代理充当用户和互联网之间的中介,提供各种功能以增强安全性、隐私性和可访问性。在众多代理类型中ÿ…...
maven-jar-plugin maven打包插件笔记
文章目录 配置示例 其他官网文档问题maven打包插件是如何和打包动作关联在一起的?配置文件中 goal是必须的吗? maven自定义插件内容很多,也不易理解,这里把maven打包插件单拿出来,作为入口试着理解下。 配置示例 <plugin><groupI…...

云服务器部署Neo4j
文章目录 导读安装Neo4j先去官网看看下载安装包如果真的下载了rpm安装包 插件 导读 大模型,他终于来了。 不过呢,大模型相关,现在也就跟着热点去尝试一下multi-agent的RAG方向,看看能做到什么地步。总之我们先从安装neo4j开始。…...
day64 图论 图论理论基础 深搜 广搜 98. 所有可达路径
图论理论基础 图的种类 整体上一般分为 有向图 和 无向图。 度 无向图中有几条边连接该节点,该节点就有几度。 在有向图中,每个节点有出度和入度。 出度:从该节点出发的边的个数。 入度:指向该节点边的个数。 连通性 在图…...

从0进入微服务需要了解的基础知识
文章目录 系统架构演化过程为什么要了解系统架构的演化过程技术发展认知技术选型与创新 演变过程单体架构分层-分布式集群微服务 分布式\集群\微服务 微服务中的核心要素-拆分原则项目拆分与复杂度微服务的拆分维度有哪些小结 微服务中的核心要素服务化进行拆分后一定是微服务&…...

MySQL之复制(七)
复制 定制的复制方案 分离功能 许多应用都混合了在线事务处理(OLTP)和在线数据分析(OLAP)的查询。OLTP查询比较短并且是事务型的。OLAP查询则通常很大,也很慢,并且不要求绝对最新的数据。这两种查询给服务器带来的负担完全不同,因此它们需…...

Redis分片集群搭建
主从模式可以解决高可用、高并发读的问题。但依然有两个问题没有解决: 海量数据存储高并发写 要解决这两个问题就需要用到分片集群了。分片的意思,就是把数据拆分存储到不同节点,这样整个集群的存储数据量就更大了。 Redis分片集群的结构如…...
请解释Java中的策略模式,并举例说明其应用场景和实现方式。请解释Java中的模板方法模式,并讨论其在实际项目中的应用。
请解释Java中的策略模式,并举例说明其应用场景和实现方式。 策略模式(Strategy Pattern) 策略模式是一种行为设计模式,它使你能够定义一系列算法,并将每一个算法封装起来,使它们可以互相替换。策略模式使…...

Vim基础操作:常用命令、安装插件、在VS Code中使用Vim及解决Vim编辑键盘错乱
Vim模式 普通模式(Normal Mode): 这是 Vim 的默认模式,用于执行文本编辑命令,如复制、粘贴、删除等。在此模式下,你可以使用各种 Vim 命令来操作文本。插入模式(Insert Mode)&#…...

基于Windows API DialogBox的对话框
在C中,DialogBox函数是Windows API的一部分,它用于在Win32应用程序中创建并显示一个模态对话框。DialogBox函数是USER32.DLL中的一个导出函数,因此你需要在你的C Win32应用程序中链接到这个库。 #include "framework.h" #include …...

五十一、openlayers官网示例Layer Min/Max Resolution解析——设置图层最大分辨率,超过最大值换另一个图层显示
使用minResolution、maxResolution分辨率来设置图层显示最大分辨率。 <template><div class"box"><h1>Layer Min/Max Resolution</h1><div id"map" class"map"></div></div> </template><…...

24年计算机等级考试22个常见问题解答❗
24年9月计算机等级考试即将开始,整理了报名中容易遇到的22个问题,大家对照入座,避免遇到了不知道怎么办? 1、报名条件 2、报名入口 3、考生报名之后后悔了,不想考了,能否退费? 4、最多能够报多少…...

obsidian制作自己的主题一文入门
制作自己的主题 我最近发现一款插件,直接把obsidian的文章格式复制到公众号中。 我非常喜欢这个功能,这将减少公众号排版的时间,同时保持公众号文章格式的一致性。 但是这个插件提供的模板不能满足我的需求,所以,需要…...
游戏心理学Day20
扩展的8种玩家 完成主义者 此类玩家关心的是成就和进展,其主要目的是完成游戏的主要目标,其次是完成游戏的次要目标之后才是游戏中的其他内容,在多人游戏中完成主义者会致力于炫耀自己的状态和财富。如果游戏以胜负为目标,那么此…...

Serverless如何赋能餐饮行业数字化?乐凯撒思变之道
导语 | 在数字化浪潮席卷全球的今天,每一个行业都在经历着前所未有的变革。餐饮行业作为人们日常生活中不可或缺的一部分,更是面临着巨大的转型压力。如何完成数字化转型,打破传统经营模式的限制,成为摆在众多餐饮商家面前的一道难…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...

软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...