代码编织梦想

Redis的高性能是因为它是一个基于内存存储计算的非关系型数据库,这就导致它存在一个严重的问题:一旦服务器宕机,内存中的数据将全部消失。
目前,Redis有两种持久化方式:

  • AOF(Append Only File)日志
  • RDB(Redis DataBase)快照

AOF实现及原理

Redis写日志的逻辑是先执行命令,把数据写入内存中,再执行写日志操作。而我们知道的MySQL的WAL(全称:Write-Ahead Logging)预写日志系统却是先写日志(undo log,redo log,binlog),再执行数据的实际写入,防止发生故障时进行恢复。

首先我们要知道,MySQL的写操作是随机IO,且是要写入磁盘的,比较耗性能,先写入日志,就变成了顺序写入,再有后台线程以异步的方式去更新数据,同时大大降低了IO的次数,从而提供性能。

而Redis本身就是往内存中写数据,那么AOF先执行命令后记日志的原因是什么呢?Redis是为了避免命令语句的正确性检查开销。要是当Redis先向AOF里面记录日志,且没有对这些操作命令做语法检查,那么记录的日志将是错误的操作命令。一是这根本是一条错误的无效命令,没有发生对应数据的增量或更改;二是当使用该日志恢复数据时,执行该条命令时就会发生错误。而这种先写后记录日志的方式,可以避免以上错误,只有当命令执行成功时,Redis才会去执行日志的操作,否者,会直接抛出异常。除此之外,我们知道Redis是“单线程”的,所以AOF还有一个好处:它是在执行完命令之后再记录日志,因此不会阻塞当前的写操作。

顺序执行的操作都会存在一个风险,如果刚执行完一个命令,还没写入,服务器就宕机了,那么这条数据就会无法恢复。同时写入操作也会带来一定的风险,当AOF日志在主线程中执行写入磁盘时,当磁盘写压力大时,写入变得很慢,从而影响后续的操作被阻塞。

对于上述问题,Redis给我们提供了三种写回策略,通过配置项appendfsync决定。

  • Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘。
  • Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘。
  • No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

三种写回策略,各有优缺点,总结如下表。

appendfsync配置项写会时机优点缺点
Always同步写回可靠性高,数据基本不会丢失每个性能都要落盘,性能较差
Everysec每秒写回性能适中宕机时丢失1s的数据
No操作系统控制写回性能好宕机时丢失离上次写回后的数据

同时AOF如其名,是以文件追加的方式写入,随着写入的命令越来越多,文件也会越来越大,这个时候,AOF重写机制就上场了。简单来说,就是对旧的AOF日志文件进行压缩精简,把一些重复的操作以及最终目标数据一致的多条操作,多变一,精简成单条命令。

RDB实现及原理

AOF日志记录的是操作命令,日志一多,恢复数据时需要再次执行这些命令,会比较耗时,影响上层应用的正常使用。RDB相比AOF,记录的是内存中某一时刻的数据状态,而且RDB文件是一个二进制文件,
结构非常紧凑,可以加速数据恢复。

Redis提供了两个命令来生成RDB文件。

  • save:在主线程中执行,会导致阻塞。
  • bgsave:创建一个子进程,专门用来写入RDB文件,避免了主线程的阻塞,这也是Redis RDB文件默认的生成方式。

bgsave子线程是Redis主线程fork生成的,可以共享主线程的所有内存数据,若在快照执行期间内,数据被改动了,那该怎么办。为了快照而阻塞主线程的写操作,肯定是不可取的,这个时候,Redis会借助操作系统的COW(Copy-On-Write)写时复制。简单来说,就是主线程要修改一块数据是,这块数据会被copy一份,生成副本;然后,主线程在这个副本上对数据做修改操作;同时,bgsave子进程就可以继续读取原来的文件,写入到RDB文件中,从而避免了对主线程写操作的影响。

但是RDB频繁的执行快照,也会给系统带来压力。一发面是频繁的写操作,会给磁盘带来压力,频繁的快照可能导致上一个快照还没有落盘,下一个快照就又开始了,导致各种异常情况。另一方面是bgsave子线程虽然执行期间不影响主线程,但是它需要通过主线程fork操作创建出来,这个过程是在主线程中执行的,是会阻塞主线程的,频繁的快照,也会导致主线程执行频繁的fork操作,从而阻塞主线程的其他操作。

有什么好的办法来解决上述问题吗?结合AOF和RDB各自的优缺点,Redis4.0之后,可以混合使用二者。内存快照按一定的频率执行,两次快照之前,使用AOF来记录期间的操作命令。这样一来,快照不用很频繁地执行,也就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/HeroNet2010/article/details/127234326

redis持久化和数据恢复的坑_p7+的博客-爱代码爱编程

redis提供了rdb和aof两种持久化机制,rdb默认开启,aof默认关闭。 当两种持久化机制都开启时,redis重启恢复数据时加载aof持久化的appendonly.aof文件,而rdb持久化的dump.rdb文件不会

redis介绍_lemon lime的博客-爱代码爱编程

redis介绍 一,Redis简介 · Redis是一个开源的(BSD许可)的,内存中的数据结构存储系统。使用c语言编写,支持网络,可基于内存也可持久化的日志型,key-value数据库。它可以用做数据库,缓存和消息中间

redis数据丢失_有效避免数据丢失!Redis持久化方案选择详解-爱代码爱编程

为什么需要持久化呢? 通常情况下redis的数据全部存储在内存中,数据库一旦故障发生重启数据会全部丢失,即使是在redis cluster或者redis sentinel模式下主从同步数据的恢复仍然需要一段时间。 持久化功能在于能够有效地避免因进程退出造成的数据丢失问题,在下次重启时利用之前持久化的文件即可实现数据恢复。 开启Redis

redis持久化(万一redis突然宕机了咋办?数据会丢失吗?)-爱代码爱编程

回答标题问题:不会丢失。 先来说说什么是数据持久化,为啥要进行数据持久化。 第一点:什么是数据持久化。        在缓存服务中,我们都了解,他说一种高速缓冲,存放于内存的一种服务。那么内存中的东西生命周期是什么呢?通常来说,当机器关闭的时候,内存中的数据都会清空,都不会存储,那么下次开机的时候,不会出现之前的数据。那么为了防止这种情况突然

redis详解_嗑嗑太可了。的博客-爱代码爱编程

转载:Redis 详解_罗志宏的博客-CSDN博客_redis详解 1. 什么是 Redis   Redis 是一个基于内存的高性能 key-value 数据库。是完全开源免费的,用C语言编写的,遵守BSD协议。   Redis 特点: Redis 是基于内存操作的,吞吐量非常高,可以在 1s内完成十万次读写操作 Redis 的读写模块是单线程,

【学习笔记】redis 持久化机制_left_zzzz的博客-爱代码爱编程

持久化的作用 Redis是内存型数据库,如果在运行过程中断电,内存数据会丢失。但是Redis提供了持久化机制,让Redis能在意外发生后能重新恢复原有数据。 AOF持久化策略 AOF(Apend Only File)是

redis的简介_dongdongdongjl的博客-爱代码爱编程

1、什么是Redis? Redis,英文全称是Remote Dictionary Server(远程字典服务),是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,

redis学习笔记【持续更新中】-爱代码爱编程

一、Redis概述 1.是什么 是存在内存中的数据库 是Key-Value数据库(MySQL是关系数据库) 2.能干什么 一个程序大部分都是查询,少部分是写入 所以用MySQL作存储,Redi

redis简述|以及它能用于做什么?_redis一般用来干嘛-爱代码爱编程

什么是Redis Redis是一种开源的NoSQL内存数据库,用于高性能的数据存储和访问。Redis支持多种数据类型,包括字符串、哈希、列表、集合和有序集合,并且支持分布式存储和操作。Redis的特点包括快速、高可用和易扩展等,适用于各种应用场景。 Redis应用场景 Redis可以广泛应用于多种场景,包括但不限于以下几种: 1. 缓

redis详细讲解-爱代码爱编程

一、Redis介绍                  Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。         redis是一个key-value存储系统。和Memcached类似,