百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

Redis怎么保证重启后数据不丢失(redis-server重启)

mhr18 2024-11-06 10:56 29 浏览 0 评论

Redis中的数据是存放在内存中的,这使得Redis拥有非常高效的读写性能。然而,内存中的数据会随着系统重启而丢失,那么 Redis 是如何保证数据不丢失的呢?

持久化

Redis 的持久化主要有两大机制,即 AOFAppend Only File)日志和 RDB(Redis DataBase) 快照」 。还有一种是混合持久化方式,并不是全新的持久化方式,而是对已有的方式的优化,Redis 4.0 之后新增的方式。混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能减低数据丢失的风险。

AOF

AOF(Append-Only File),它将所有的写操作追加到一个日志文件中,以记录数据库的状态。也就是说,在实际写数据前,先把修改的数据记到日志文件中,以便故障时进行恢复。下面是AOF日志的实现原理:

在AOF日志中,Redis收到的"set testkey testvalue"命令会被记录为如下格式的文本:

让我来解释一下这个文本的含义:

  • *3 表示当前命令有三个部分,即有三行命令。在这个例子中,这三行分别是"SET"、"testkey"和"testvalue"。
  • $3 表示后面紧跟着的部分有3个字节,也就是一个命令或者键的长度。
  • SET 是命令部分,表示这个操作是一个SET命令。
  • $7 表示后面紧跟着的部分有7个字节,也就是键的长度。
  • testkey 是键部分,表示要设置的键名为"testkey"。
  • $9 表示后面紧跟着的部分有9个字节,也就是值的长度。
  • testvalue 是值部分,表示要设置的值为"testvalue"。

写后日志的优势在于能够避免记录错误命令,并且不会阻塞当前的写操作。这种方式确保了只有成功执行的命令才会被记录到日志中,同时也不会影响当前的写操作。

然而,AOF 模式也存在一些风险。首先,如果在执行完一个命令后还未来得及记录到日志就宕机了,那么这个命令和相应的数据就有丢失的风险。其次,AOF 日志的写回操作可能会导致磁盘写压力大,从而影响后续操作的执行。

针对这些风险,可以通过控制写命令执行完后 AOF 日志写回磁盘的时机来解决。这样可以降低丢失数据的风险,并减少对后续操作的影响。

日志的写回策略

这三种写回策略都存在一定的权衡和局限性。它们在避免主线程阻塞和减少数据丢失之间做出了不同的权衡。

  • Always 同步写回策略可以最大程度地保证数据的安全性,每个写命令执行完后都会立即将日志同步写回磁盘。这样可以避免数据丢失的风险,但会对性能产生较大影响,因为每个写操作都需要等待磁盘写入完成才能继续执行后续操作,可能导致主线程阻塞。
  • Everysec 每秒写回策略则通过将日志先写入内存缓冲区,每秒批量写回磁盘,来平衡数据安全性和性能。这种方式可以降低主线程的阻塞时间,提高性能,但在发生故障时可能会丢失最近一秒的数据。
  • No 操作系统控制的写回策略则完全依赖操作系统来决定何时将日志从内存缓冲区写回磁盘。这种方式可以最大程度地提高性能,减少主线程的阻塞时间,但也增加了数据丢失的风险,因为在发生故障时可能会丢失部分未写入磁盘的日志数据。
  • 如果对系统的性能要求比较高,可以采用 No 策略。
  • 如果对系统的可靠性要求比较高,可以采用 Always 策略。
  • 如果既希望保证数据的可靠性,又希望性能不受太大影响,可以采用 Everysec 策略。

然而,仅仅根据系统性能需求选择写回策略并不能完全保障系统的顺利运行。这是因为AOF以文件形式记录接收到的所有写命令。随着写命令的不断增加,AOF文件会变得越来越大。这会引发性能问题。

日志文件太大了怎么办?

AOF重写机制是解决AOF文件过大问题的一种有效措施。它通过重新构建AOF文件,只保留可以恢复当前数据库状态的最小命令集合,从而实现AOF文件的精简和压缩。

AOF重写机制的基本原理是,Redis会在后台创建一个新的AOF文件,然后通过遍历数据库的方式将当前数据库状态以命令的形式写入新的AOF文件。在这个过程中,Redis会跳过那些在重写期间已经被修改的键,而只记录键的最新值。这样可以大大减小新AOF文件的大小。

AOF重写机制的好处有:

  1. 减小AOF文件的大小,节省存储空间。
  2. 提高AOF文件的性能,减少磁盘IO操作,加快恢复速度。
  3. 降低系统负载,减少AOF文件写入的时间消耗。

需要注意的是,AOF重写机制是一个后台任务,在Redis运行时会自动触发。您可以通过配置参数来调整重写的触发条件和频率,以满足不同的需求。

重写的过程

和 AOF 日志由主线程写回不同,重写过程是由后台线程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。

我把重写的过程总结为“一个拷贝,两处日志”。

在AOF日志重写过程中,主线程通过fork创建后台的bgrewriteaof子进程,将数据库的最新数据拷贝一份给子进程。子进程可以在不影响主线程的情况下,逐一将拷贝的数据写成操作,并记录到重写日志中。

第一处日志指的是主线程仍然可以处理新操作,Redis会将这些操作写入其缓冲区,即使发生宕机,AOF日志的操作仍然是完整的,可以用于恢复。

第二处日志是指新的AOF重写日志,这些操作也会被写入重写日志的缓冲区,确保不会丢失最新的操作。当所有拷贝数据的操作记录重写完成后,重写日志中记录的这些最新操作也会被写入新的AOF文件,以保证数据库的最新状态得到记录。

此时,我们就可以用新的 AOF 文件替代旧文件了。

总结来说,每次 AOF 重写时,Redis 会先执行一个内存拷贝,用于重写;然后,使用两个日志保证在重写过程中,新写入的数据不会丢失。而且,因为 Redis 采用额外的线程进行数据重写,所以,这个过程并不会阻塞主线程。

RDB

RDB文件实际上是一个持久化的快照,记录了某一时刻的数据库状态,包括其中的所有键值对和其对应的数据。

与AOF日志不同,RDB文件并不记录操作的历史,而是直接记录了数据库在某个时间点的完整状态。这种方式的好处是,在进行数据恢复时,可以直接将RDB文件读入内存,迅速地完成数据库的恢复。由于RDB文件只是一个二进制数据文件,因此在加载和解析上会比AOF日志更加高效。

快照的原理

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 的配置选项,因为它在可靠性和性能之间取了一个平衡。

相关推荐

如何检查 Linux 服务器是物理服务器还是虚拟服务器?

在企业级运维、故障排查和性能调优过程中,准确了解服务器的运行环境至关重要。无论是物理机还是虚拟机,都存在各自的优势与限制。在很多场景下,尤其是当你继承一台服务器而不清楚底层硬件细节时,如何快速辨识它是...

第四节 Windows 系统 Docker 安装全指南

一、Docker在Windows上的运行原理(一)架构限制说明Docker本质上依赖Linux内核特性(如Namespaces、Cgroups等),因此在Windows系统上无法直...

C++ std:shared_ptr自定义allocator引入内存池

当C++项目里做了大量的动态内存分配与释放,可能会导致内存碎片,使系统性能降低。当动态内存分配的开销变得不容忽视时,一种解决办法是一次从操作系统分配一块大的静态内存作为内存池进行手动管理,堆对象内存分...

Activiti 8.0.0 发布,业务流程管理与工作流系统

Activiti8.0.0现已发布。Activiti是一个业务流程管理(BPM)和工作流系统,适用于开发人员和系统管理员。其核心是超快速、稳定的BPMN2流程引擎。Activiti可以...

MyBatis动态SQL的5种高级玩法,90%的人只用过3种

MyBatis动态SQL在日常开发中频繁使用,但大多数开发者仅掌握基础标签。本文将介绍五种高阶技巧,助你解锁更灵活的SQL控制能力。一、智能修剪(Trim标签)应用场景:动态处理字段更新,替代<...

Springboot数据访问(整合Mybatis Plus)

Springboot整合MybatisPlus1、创建数据表2、引入maven依赖mybatis-plus-boot-starter主要引入这个依赖,其他相关的依赖在这里就不写了。3、项目结构目录h...

盘点金州勇士在奥克兰13年的13大球星 满满的全是...

见证了两个月前勇士与猛龙那个史诗般的系列赛后,甲骨文球馆正式成为了历史。那个大大的红色标志被一个字母一个字母地移除,在周四,一切都成为了过去式。然而这座,别名为“Roaracle”(译注:Roar怒吼...

Mybatis入门看这一篇就够了(mybatis快速入门)

什么是MyBatisMyBatis本是apache的一个开源项目iBatis,2010年这个项目由apachesoftwarefoundation迁移到了googlecode,并且改名为M...

Springboot数据访问(整合druid数据源)

Springboot整合druid数据源基本概念SpringBoot默认的数据源是:2.0之前:org.apache.tomcat.jdbc.pool.DataSource2.0及之后:com.z...

Linux 中的 &quot;/etc/profile.d&quot; 目录有什么作用 ?

什么是/etc/profile.d/目录?/etc/profile.d/目录是Linux系统不可或缺的一部分保留配置脚本。它与/etc/profile文件相关联,这是一个启动脚本,该脚...

企业数据库安全管理规范(企业数据库安全管理规范最新版)

1.目的为规范数据库系统安全使用活动,降低因使用不当而带来的安全风险,保障数据库系统及相关应用系统的安全,特制定本数据库安全管理规范。2.适用范围本规范中所定义的数据管理内容,特指存放在信息系统数据库...

Oracle 伪列!这些隐藏用法你都知道吗?

在Oracle数据库中,有几位特殊的“成员”——伪列,它们虽然不是表中真实存在的物理列,但却能在数据查询、处理过程中发挥出意想不到的强大作用。今天给大家分享Oracle伪列的使用技巧,无论...

Oracle 高效处理数据的隐藏神器:临时表妙用

各位数据库搬砖人,在Oracle的代码世界里闯荡,处理复杂业务时,是不是总被数据“搅得头大”?今天给大家安利一个超实用的隐藏神器——临时表!当你需要临时存储中间计算结果,又不想污染正式数据表...

Oracle 数据库查询:多表查询(oracle多表关联查询)

一、多表查询基础1.JOIN操作-INNERJOIN:返回两个表中满足连接条件的匹配行,不保留未匹配数据。SELECTa.emp_id,b.dept_nameFROMempl...

一文掌握怎么利用Shell+Python实现多数据源的异地备份程序

简介:在信息化时代,数据安全和业务连续性已成为企业和个人用户关注的焦点。无论是网站数据、数据库、日志文件,还是用户上传的文档、图片等,数据一旦丢失,损失难以估量。尤其是当数据分布在多个不同的目录、服务...

取消回复欢迎 发表评论: