Redis: 持久化之RDB和AOF

news2024/10/3 0:12:36

概述

  • Redis 有一个高质量的课题:数据安全性与数据可靠性
  • Redis 是一个内存型数据库,数据大部分都是存在内存里面
  • 当信息在内存中流通时,Redis 节点突然就故障挂掉
  • 当重新启动的时候,内存中的数据肯定是全部丢失了
  • 如果在这种情况下,Redis 提供了对应的持久化方案,它有两种持久化方案
    • RDB和AOF可以把内存中的数据保存到磁盘,避免数据的流失
  • 关于RDB,我们需要了解到
    • 什么是持久化
    • 什么是快照
    • RDB的工作原理,包括它的优点和缺点
  • 关于AOF,需要知道
    • 为什么需要有AOF
    • 存储上线后重写,为什么要重写,以及其触发条件
    • 文件如何写入,文件损坏了怎么办
    • 它是一个备选方案,或者说一种增强方案
  • Redis 既然有了RDB又提供了AOF, 肯定两者之间是会有一个互补的关系
    • 这里的话, 我们要去讲他们两者该如何选择, 如何互补?
    • 该开启RDB还是开启AOF, 还是说同时都开启
    • 同时都开启的情况下,数据冗移是需要考虑
    • 从 RDB 动态切换到 AOF 在 Redis 不重启的情况下并保证数据不丢失,如何实现
  • 关于 Redis 的备份容灾
    • 比如说我们写一个脚本
    • 再来一个定时任务,定时的去执行脚本
    • 把我们的数据给它备份起来
    • 备份了之后,怎么去恢复呢?如何更好的去恢复
  • 关于Redis 的优化方案
    • 更好的提升性能,从硬盘角度,从fork进程角度
    • 以及从主从的角度

Redis 持久化方式

1 )通常数据库存在三种用于持久操作以防止数据损坏的常见策略:

  • 是数据库不关心故障,而是在数据文件损坏后从数据备份或快照中恢复,RDB就是这种情况
  • 该数据库使用操作日志记录每个操作的操作行为,以在失败后通过日志恢复一致性。由于操作日志是按顺序追加写入的,因此不会出现无法恢复操作日志的情况。类似于Mysql的重做(redolog)和撤消日志(undolog)
  • 数据库不修改旧数据,而仅通过追加进行写入,因此数据本身就是日志,因此永远不会出现数据无法恢复的情况。CouchDB是一个很好的例子,AOF类似这种情况

2 )严格上讲Redis为持久化提供了三种方式:

  • RDB:在指定的时间间隔能对数据进行快照存储,类似于MySQL的dump备份文件
  • AOF:记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据(MySQL的binlog)
  • RDB与AOF混合使用,这是Redis4.0开始的新特性,在混合使用中AOF读取RDB数据重建原始数据集,集二者优势为一体

RDB持久化


1 )初始化环境

1.1 创建配置/数据/日志目录

# 创建配置目录
mkdir -p /usr/local/redis/conf
# 创建数据目录
mkdir -p /usr/local/redis/data
# 创建日志目录
mkdir -p /usr/local/redis/log

1.2 配置文件

  • 创建一份配置文件至 conf 目录

    vim /usr/local/redis/conf/redis.conf
    
  • 文件内容如下

    # 放行访问IP限制
    bind 0.0.0.0
    
    # 后台启动
    daemonize yes
    
    # 日志存储目录及日志文件名
    logfile "/usr/local/redis/log/redis.log"
    
    # rdb数据文件名 持久化后生成的文件
    dbfilename dump.rdb
    
    # rdb数据文件和aof数据文件的存储目录
    dir /usr/local/redis/data
    
    # 设置密码
    requirepass 123456
    
  • 通过这个配置文件,启动: bin/redis-server conf/redis.conf

  • 验证:ps -ef | grep redis

  • 客户端连接 bin/redis-cli -a 123456

    • 这里密码明文不推荐,仅供参考

1.3 数据准备

  • 查看数据库数据大小:$ DBSIZE 目前新环境没有任何数据显示 0
  • 插入一些数据来演示RDB中一些阻塞的命令,若数据集较小则看不到任何效果
  • 我们通过一个python文件,循环插入 500 w 数据,使用 redis 管道的方式来插入大概30s-1min
    • 不用管道,则可能要 30min-1h, 非常慢
  • $ cd bin/ && vim initdata.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Token(object):
	def __init__(self, value):
		if isinstance(value, Token):
			value =value.value
		self.value =value

	def _repr_(self):
		return self.value
		
	def __str__(self):
		return self.value
	
def b(x):
	return x


SYM_STAR = b('*')
SYM_DOLLAR = b('$')
SYM_CRLF = b('\r\n')
SYM_EMPTY = b('')

class RedisProto(object):

def __init__(self, encoding='utf-8', encoding_errors='strict'):
	self.encoding = encoding
	self.encoding_errors = encoding_errors

def pack_command(self, *args):
	"""将redis命令安装redis的协议编码,返回编码后的数组,如果命令很大,返回的是编码后chunk的数组"""
	output =[]
	command = args[0
	if '' in command:
		args = tuple([Token(s) for s in command. split('')])+ args[1:]
	else:
		args =(Token(command),)+ args[1:]

	buff = SYM_EMPTY.join((SYM_STAR, b(str(len(args))), SYM_CRLF))

	for arg in map(self.encode, args):
		"""数据量特别大的时候,分成部分小的chunk"""
		if len(buff) > 6000 or len(arg) > 6000:
			buff = SYM_EMPTY.join((buff, SYM_DOLLAR, b(str(len(arg))
			output.append(buff)
			return output


def encode(self, value):
	if isinstance(value, Token):
		return b(value.value)
	elif isinstance(value, bytes):
		return value
elif isinstance(value, int):
value = b(str(value))
elif not isinstance(value, str):
value = str(value)
if isinstance(value, str):
value= value.encode(self.encoding, self.encoding_errors)
return value

if _name_ == '_main_':
for i in range(5000000):
commands_args = [('SET', 'key_'+ str(i), 'value_'+ str(i))]
commands = ''.join([RedisProto().pack_command(*args)[0] for args in commands_args])
print commands

  • 执行 python initdata.py | ./redis-cli -a 123456 --pipe
  • 过个几十秒,查看 $ DBSIZE
  • 之后,查看内存使用情况:$ info memory 可看到,大约 438M 的内存占用
  • 进入 data 目录查看 dump.rdb 是否生成,发现并没有,说明RDB持久化并没有去做
  • 如果强制被 kill 掉 redis 模拟故障,内存数据将会全部丢失,所以需要对内存数据做持久化处理
  • 在一些业务场景下,内存数据是需要被保存下来的,就需要设置 RDB
  • 现在修改配置文件 $ vim conf/redis.conf, 添加如下,并重启 redis
    # 5秒有一个key的改动,就执行快照生成
    save 5 1
    
  • 这么这个配置用来模拟我们的故障,实际上缺省配置如下
    # 900秒内如果超过1个key改动,则发起快照保存
    save 900 1
    
    # 300秒内如果超过10个key改动,则发起快照保存
    save 300 10
    
    # 60秒内如果超过1W个key改动,则发起快照保存
    save 60 10000
    
  • 还是通过模拟故障的配置来看
  • 启动后,重新执行py脚本插入数据
  • 数据插入完成后,进入 data 目录,发现已经有 dump.rdb 文件了
    • 而且还多了 temp-1428.rdb 类似的文件
    • 这个 temp 文件是其内部的生成工作原理
  • 再次模拟故障,可发现数据仍存在
  • 因为我们配置中写的是 5s, 那如果配置成 15min 的时间,那没有生成快照数据还会丢失
  • AOF的出现,弥补了这一个缺陷

Redis 快照

  • 快照,顾名思义可以理解为拍照一样,把整个内存数据映射到硬盘中,保存一份到硬盘,因此恢复数据起来比较快,把数据映射回去即可,不像AOF,一条条的执行操作命令
  • 快照是默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb,可以通过配置设置自动做快照持久化的方式
  • 产生快照的情况有以下几种:
    • 手动 bgsave 执行
    • 手动 save 执行
    • 注意:
      • BGSAVE 命令是非阻塞的
        • 本质上是folk出一个子进程在后台做快照生成, 仍然能对外提供服务
        • 对外提供的是 get ,但是 save 这种写操作就不一样了
      • SAVE 命令是阻塞的
        • 主进程来做这件事,你来访问我的时候
        • 我在忙的时候肯定提供不了服务给你
      • 同时,SHUTDOWN 命令也是阻塞的
        • 要先保存好数据
    • 根据配置文件自动执行
    • 客户端发送 shutdown, 系统会先执行 save 命令阻塞客户端,然后关闭服务器
    • 当有主从架构时,从服务器向主服务器发送sync 命令来执行复制操作时,主服务器会执行 bgsave操作

RDB 工作原理

  • Redis默认会将快照文件存储在Redis当前进程的工作目录中的dump.rdb文件中

  • 可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名

  • 流程过程如下(rdb.c中)

  • 这个图,也是通过源码 rdb.c 来总结的

  • serverCron 是一个循环时间事件函数

    • 这个函数它的作用就是来监控配置文件的
    • 它就监控配置文件里边的save配置项
    • 当这个时间满足,就开始触发,触发之后,最终也会执行 bgsave 的底层流程
  • bgsave 内部调用 bgsaveCommand, 它fork子进程做持久化,是非阻塞的

  • save 也是调用 saveCommand, 它是主进程的,它会阻塞,不对外提供读的服务,全心全意持久化

  • 也就是说:serverCron, bgsave, save 三者都在做持久化的事情,都会有 rdbSave的流程

    • 先写一个 temp 的文件
    • 然后这个临时文件开启之后,会把之前的数据先全部通通的加载过来
    • 加载过来之后,把新的内存里边的数据给它写进去
    • 写进去持久化之后,然后刷新,关闭
    • 关闭以后,把这个临时文件内改一个名字,再改成原始的你的文件名把它覆盖一下
    • 这个就对应上面 temp-1428.rdb 的文件
  • 这就是 Redis RDB的一个工作原理

RBD的优缺点

1 )优点

  • 紧凑压缩的二进制文件
    • $ vim dump.rdb 可看到
    • 备份非常简单
  • fork子进程性能最大化
    • 非阻塞,可对外继续提供服务
  • 启动效率高
    • 二进制文件,读取数据快

2 )缺点

  • 生成快照的时机问题
    • save 5 1 这种 5s 触发一次只是我们的模拟
    • 一般生产会配置 15min 和 30min, 在较长的时间窗口期宕机,数据也会丢失
  • fork子进程的开销问题
    • 数据集比较大,频繁做这件事,会导致性能开销

AOF持久化

  • 它也是Redis持久化的重要手段之一,AOF(Append Only File)只追加文件
  • 也就是每次处理完请求命令后都会将此命令追加到aof文件的末尾
  • 而RDB是压缩成二进制等时机开子进程去干这件事
  • 弥补了save配置时间内宕机风险的问题

1 ) 开启AOF

  • 通过配置进行启动,默认是关闭的

    # 默认 appendonly 为 no
    appendonly yes
    appendfilename "appendonly. aof"
    
    # RDB文件和AOF文件所在目录
    dir /usr/local/redis/data
    
  • 基于此,我们可以开启两个窗口验证下

    • 窗口1,追踪文件变动,执行 $ tail -f data/appendonly.aof
      • 这个文件中会记录写命令,不会记录读命令
    • 窗口2,进行读写操作,执行 $ set username zhagnsan 这是写命令
  • 在窗口1 中,输出

    *2
    $6
    SELECT
    $1
    0
    *3
    $3
    SET
    $8
    username
    $8
    zhangsan
    
    • 这里, *2 代表下面2行是命令,*3表示下面三行是命令
    • $6 不在行计算范围内,$6 表示命令的字节长度 SELECT 长度是6
    • 可忽略 $ 相关来看, 就是:
      • SELECT 0
      • set username zhangsan
  • 所以,可见,aof 文件的优点是易读,缺点是容易让人读不懂

  • 这样,即使 dump 文件被删除,也可以通过 aof 来恢复了

2 )同步策略

  • Redis中提供了3种AOF同步策略:
    • 每秒同步(默认,每秒调用一次fsync,这种模式性能并不是很糟糕)
    • 每修改同步(会极大消弱Redis的性能,因为这种模式下每次 write后都会调用 fsync)
    • 不主动同步(由操作系统自动调度刷磁盘,性能是最好的, 注意:不主动不代表不写入)
  • 参考
    #每秒钟同步一次,该策略为AOF的缺省策略
    appendfsync everysec
    #每次有数据修改发生时都会写入AOF文件
    appendfsync always
    #从不同步。高效但是数据不会主动被持久化
    appendfsync no
    

3 )AOF 工作原理

  • client ----> Redis Server ----> 执行命令 ----> 命令写入AOF缓冲区 ----> 刷新磁盘写入AOF文件

  • 解释一下

    • AOF的频率高的话肯定会对Redis带来性能影响,因为每次都是刷盘操作
    • 跟mysql一样了,Redis每次都是先将命令放到缓冲区
    • 然后根据具体策略(每秒/每条指令/缓冲区满)进行刷盘操作
    • 如果配置的always,那么就是典型阻塞,如果是everysec
    • 每秒的话,那么会开一个同步线程去每秒进行刷盘操作,对主线程影响稍小

4 )写入文件与恢复

  • AOF文件是一个只进行append操作的日志文件,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。假如一次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过 redis-check-aof 工具来帮助我们修复问题。

  • AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松

  • 导出(export)AOF文件也非常简单:举个例子,如果你不小心执行了 FLUSHALL 命令,但只要AOF文件未被重写,那么只要停止服务器,移除AOF文件末尾的 FLUSHALL 命令,并重启Redis, 就可以将数据集恢复到 FLUSHALL 执行之前的状态

5 )重写

  • Redis 可以在AOF 文件体积变得过大时,自动地在后台对AOF 进行rewrite。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行

  • 因为Redis在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失

  • 而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作

  • 为什么要重写

    • 比如我有业务很简单,就来回 delete set 同一个key
    • 就这个业务运行了10年,那么aof文件将记录无数个delete k1,set k1 xxx
    • 其实都是重复的,但是我aof每次都追加,文件变成了1T大小
    • 这时候Redis宕机了,要恢复,你想想1TB大小的aof文件去恢复,累死了
    • 最主要的是1TB大小只记录了两个命令,所以压缩其实就是来处理这件事的
  • rewrite触发条件

    • 当 aof 文件越来越大,恢复的时候会降低性能
    • 客户端执行 bgrewriteaof 命令,内部有些配置什么时候重写
      • auto-aof-rewrite-min-size 64mb 这里文件超过 64m的时候会重写,生产环境要配置大些
      • auto-aof-rewrite-percentage 100 这种是按百分比来配置的

7 )常用的配置

# fsync 持久化策略
appendfsync everysec

# AOF重写期间是否禁止fsync;如果开启该选项,可以减轻文件重写时CPU和硬盘的负载(尤其是硬盘)
# 但是可能会丢失AOF重写期间的数据
# 需要在负载和安全性之间进行平衡
# 默认是 no , aof 在重写期间是可能有新的命令写入的,no则表示会记录新写入的命令,yes 则不记录
no-appendfsync-on-rewrite no

# 当前aof文件大于多少字节后才触发重写
auto-aof-rewrite-min-size 64mb

# 当前写入日志文件的大小超过上一次rewrite之后的文件大小的百分之100时,也就是2倍时触发Rewrite
auto-aof-rewrite-percentage 100

# 如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件
aof-load-truncated yes

8 )AOF 优点

  • 数据不易丢失
  • 自动重写机制 (保证aof文件不会无休止膨胀)
  • 易懂易恢复

9 )AOF缺点

  • AOF文件恢复数据慢
  • AOF持久化效率低

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL 中如何优化 DISTINCT 查询

一、引言 在 MySQL 数据库中,DISTINCT关键字用于查询结果集中去除重复的行。然而,使用DISTINCT可能会导致查询性能下降,特别是在处理大量数据时。本文将介绍一些优化 MySQL 中DISTINCT查询的方法。 二、理解 DISTINCT 查询的性能影响 &…

Oracle中TRUNC()函数详解

文章目录 前言一、TRUNC函数的语法二、主要用途三、测试用例总结 前言 在Oracle中,TRUNC函数用于截取或截断日期、时间或数值表达式的部分。它返回一个日期、时间或数值的截断版本,根据提供的格式进行截取。 一、TRUNC函数的语法 TRUNC(date) TRUNC(d…

2024/10/2

1 线代内积和外积 2 在 PyTorch 中,x.dot(torch.ones(3)) 是执行向量点积(dot product)操作的代码。假设 x 是一个一维张量(向量),其形状是 (N,),且 N 应该与 torch.ones(3) 的长度相匹配。具…

查找与排序-插入排序

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序…

java基础应用-循环控制

1、使用while与自增运算符循环遍历数组 1.1 实例说明 本实例利用自增运算符结合while循环获取每个数组元素的值,然后把它们输出到控制台中。其中自增运算符控制索引变量的递增。程序运行结果如图1所示。 图1 实例运行结果 1.2 实现过程 创建ErgodicArray类&#…

企业网盘预算规划,了解2024年最新价格标准

2024年全球企业云存储市场将增15%,企业网盘收费多样,包括用户数量、存储容量定价及综合功能套餐。ZohoWorkDrive、DropboxBusiness、GoogleWorkspace为主流选择,价格因企业规模、功能需求而异,建议灵活选择套餐和长期合作计划。 一…

yub‘s Algorithmic Adventures_Day3

yub’s Algorithmic Adventures_Day3 有序数组的平方 link:977. 有序数组的平方 - 力扣(LeetCode) 非递减顺序 一个数列中的元素从左到右依次不减,或者说不降序排列. 比如:1233445,12345. 思路分析 如果…

CORE MVC 过滤器 (筛选器)《2》 TypeFilter、ServiceFilter

TypeFilter、ServiceFilter ServiceFilter vs TypeFilter ServiceFilter和TypeFilter都实现了IFilterFactory ServiceFilter需要对自定义的Filter进行注册,TypeFilter不需要 ServiceFilter的Filter生命周期源自于您如何注册(全局、区域)&…

vite中sass警告JS API过期

1.问题 在Vite创建项目中引入Sass弹出The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0 - vite中sass警告JS API过期 The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0警告提示表明你当前正在使用的 Dart Sass 版本中&#…

Python画图|渐变背景

Python画图在有些时候,需要使用渐变过度。 在matplotlib官网中,提供了一个为柱状图画渐变背景的案例,我们一同探索一番。 【1】官网教程 点开下述链接,直达官网教程: https://matplotlib.org/stable/gallery/lines…

【Bug】解决 Ubuntu 中 “error: Unable to Find Python3 Executable” 错误

解决 Ubuntu 中 “Unable to Find Python3 Executable” 错误 在 Ubuntu 系统上使用 Python 进行开发时,遇到找不到 python3 可执行文件的错误。 主要问题是无法正常打开终端(原生与terminator),找不到python3,且无法…

基于muduo库函数实现protobuf协议的通信

文章目录 先定义具体的业务请求类型2. 实现服务端提供的服务protobuf_server.cppprotobuf_client.cpp 建议先去了解muduo库和protobuf协议: Protobuf库的使用Muduo库介绍及使用 先定义具体的业务请求类型 先使用protobuf库创建我们所要完成的业务请求类型&#xf…

域内用户名枚举 实验

1. 实验网络拓扑 kali: 192.168.72.128win2008: 192.168.135.129 192.168.72.139win7: 192.168.72.149win2012:(DC) 192.168.72.131 2. 简单原理 详细的报文分析在之前写过了,这里简单提一提。 利用的是Kerberos的AS阶段,AS_REP的回显不同&#xff0c…

迷宫中的最短路径:如何用 BFS 找到最近出口【算法模板】

如何通过广度优先搜索(BFS)求解迷宫问题 在这篇文章中,我们将学习如何使用 广度优先搜索(BFS) 解决一个典型的迷宫问题,具体是从迷宫的一个入口出发,找到最近的出口。我们将一步步分析 BFS 是如…

初识CyberBattleSim

现在许多企业都在使用AD域服务进行管理,我们现在通俗理解里面蕴含着许多重要资产。 对于这个东西有下列的描述: 1、攻击他能够获得用户权限 2、里面存在许多的计算机资产,当攻击者攻击其中的一台机器,可以通过某种手段在域中的环境横向移动…

golang rpc

RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务,对应rpc的是本地过程调用,函数调用是最常用的本地过程调用,将本地过程调用变成远程调用会面临着各种问题。 以两数…

第 21 章 一条记录的多幅面孔——事务的隔离级别与 MVCC

21.1 事前准备 CREATE TABLE hero ( number INT, NAME VARCHAR ( 100 ), country VARCHAR ( 100 ), PRIMARY KEY ( number ) ) ENGINE INNODB CHARSET utf8;INSERT INTO hero VALUES ( 1, 刘备, 蜀 );21.2 事务隔离级别 在保证事务隔离性的前提下,使用不同的隔…

【Burp入门第三十三篇】IP Rotate 插件实现IP轮换爆破

Burp Suite是一款功能强大的渗透测试工具,被广泛应用于Web应用程序的安全测试和漏洞挖掘中。 本专栏将结合实操及具体案例,带领读者入门、掌握这款漏洞挖掘利器 读者可订阅专栏:【Burp由入门到精通 |CSDN秋说】 文章目录 正文安装步骤使用步骤应用场景实战文章正文 在 Burp…

基于SpringBoot+Vue+MySQL的智能垃圾分类系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着城市化进程的加速,垃圾问题日益凸显,不仅对环境造成污染,也给城市管理带来了巨大挑战。传统的垃圾分类方式不仅费时费力,而且手工操作容易出现错误,导致垃圾分类效…

探索未来工业自动化的钥匙:OPC UA与AI的融合

文章目录 探索未来工业自动化的钥匙:OPC UA与AI的融合背景:为什么选择OPC UA?OPC UA库简介安装OPC UA库简单的库函数使用方法连接到服务器获取节点读取节点值设置节点值订阅数据变更 库的使用场景工业自动化监控能源管理系统预测性维护 常见问…