Redis基础篇(三)持久化:AOF日志
Redis是内存数据库,但是一旦服务器宕机,内存中的数据将会全部丢失。
最简单的恢复方式是从后端数据库恢复,但这种方式有两个问题:
- 频繁访问数据库,会给数据库带来巨大的压力;
- 从数据库中读取相比从Redis中读取要慢很多,会导致应用响应变慢
因此,Redis要实现持久化,避免从后端数据库中进行恢复。
Redis有两种持久化机制:AOF(Append Only File)日志和RDB快照。今天先来学习AOF日志。
什么是AOF日志?
AOF日志是通过保存Redis写命令来记录数据库数据的。大多数的数据库采用的是写前日志(WAL),例如MySQL,通过写前日志和两阶段提交,实现数据和逻辑的一致性。想了解更多关于两阶段提交的内容,点击查看。
而AOF日志采用写后日志,即先写内存,后写日志。
为什么采用写后日志?
Redis要求高性能,采用写日志有两方面好处:
- 避免额外的检查开销
- 不会阻塞当前的写操作
但这种方式存在潜在风险:
- 如果命令执行完成,写日志之前宕机了,会丢失数据。
- 主线程写磁盘压力大,导致写盘慢,阻塞后续操作。
如何实现AOF日志?
AOF日志记录Redis的每个写命令,步骤分为:命令追加(append)、文件写入(write)和文件同步(sync)。
命令追加
当AOF持久化功能打开了,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器的 aof_buf
缓冲区。
文件写入和同步
关于何时将 aof_buf
缓冲区的内容写入AOF文件中,Redis提供了三种写回策略:
Always,同步写回
:每个写命令执行完,立马同步地将日志写回磁盘;Everysec,每秒写回
:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;No,操作系统控制的写回
:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
上面的三种写回策略体现了一个重要原则:trade-off,取舍,指在性能和可靠性保证之间做取舍。
关于AOF的同步策略是涉及到操作系统的 write
函数和 fsync
函数的,在《Redis设计与实现》中是这样说明的:
为了提高文件写入效率,在现代操作系统中,当用户调用
write
函数,将一些数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区的空间被填满或超过了指定时限后,才真正将缓冲区的数据写入到磁盘里。这样的操作虽然提高了效率,但也为数据写入带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失。为此,系统提供了
fsync
、fdatasync
同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保写入数据的安全性。
如何配置AOF?
默认情况下,Redis是没有开启AOF的,可以通过配置redis.conf文件来开启AOF持久化,关于AOF的配置如下:
# appendonly参数开启AOF持久化
appendonly no # AOF持久化的文件名,默认是appendonly.aof
appendfilename "appendonly.aof" # AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
dir ./ # 同步策略
# appendfsync always
appendfsync everysec
# appendfsync no # aof重写期间是否同步
no-appendfsync-on-rewrite no # 重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb # 加载aof出错如何处理
aof-load-truncated yes # 文件重写策略
aof-rewrite-incremental-fsync yes
AOF重写
AOF会记录每个写命令到AOF文件,随着时间越来越长,AOF文件会变得越来越大。如果不加以控制,会对Redis服务器,甚至对操作系统造成影响,而且AOF文件越大,数据恢复也越慢。
为了解决AOF文件体积膨胀的问题,Redis提供AOF文件重写功能来对AOF文件进行“瘦身”。Redis通过创建一个新的AOF文件来替换现有的AOF,新旧两个AOF文件保存的数据相同,但新AOF文件没有了冗余命令。
简单来说,AOF重写就是把旧AOF日志文件的多条命令,在重写后变成新日志文件的一条命令。
AOF重写会阻塞吗?AOF重写是由后台线程bgrewriteaof来完成的。
AOF重写过程
用一句话总结:一个拷贝,两处日志。一个拷贝指一份内存拷贝,两处日志分别是一处正在使用的AOF日志,另一处是新的AOF重写日志。
下图是AOF重写过程:
拓展
关于AOF重写过程的潜在阻塞风险
前面提到AOF重写不会阻塞,指的是在AOF重写过程不会阻塞主线程,因为是通过后台bgrewriteaof线程来执行的。
但是在fork子进程的时候,fork这个瞬间一定是会阻塞主线程的。
fork采用的是操作系统提供的写时复制(Copy On Write)机制,避免一次性拷贝造成的阻塞。但fork子进程需要拷贝进程必要的数据结构,其中有一项是拷贝内存页表(虚拟内存和物理内存的映射索引表),这个拷贝过程会消耗大量的CPU资源,在拷贝完成之前,整个进程是会阻塞的。
拷贝内存页完成后,子进程与父进程指向相同的内存地址空间,也就是说此时虽然产生了子进程,但是并没有申请与父进程相同的内存大小。
那什么时候父子进程才会真正内存分离呢?在写发生时,才真正拷贝内存的数据,这个过程中,父进程也可能会产生阻塞风险。
因为内存分配是以页为单位进行分配的,默认4K,如果父进程此时操作的是一个bigkey,重新申请大块内存耗时会变长,可能会产生阻塞风险。
另外,如果操作系统开启了内存大页机制(Huge Page,页面大小2M),那么父进程申请内存时阻塞的概率将会大大提高,所以在Redis机器上需要关闭Huge Page机制。
为什么AOF重写不复用原AOF日志
有两方面原因:
- 父子进程写同一个文件会产生竞争问题,影响父进程的性能。
- 如果AOF重写过程中失败了,相当于污染了原本的AOF文件,无法做恢复数据使用。
AOF重写需要手动触发吗?
可以设置自动触发,通过配置这两个参数auto-aof-rewrite-min-size
和auto-aof-rewrite-percentage
:
auto-aof-rewrite-min-size
:表示运行AOF重写时文件的最小大小,默认为64MBauto-aof-rewrite-percentage
:当前AOF文件大小和上一次重写后AOF文件大小的差值,再除以上一次重写后AOF文件大小
当AOF文件大小同时超出上面两个配置项,会触发AOF重写。
参考资料
- Redis设计与实现
- 10分钟彻底理解Redis的持久化机制:RDB和AOF
- Redis两种持久化机制RDB和AOF详解(面试常问,工作常用)
- Redis持久化机制:RDB和AOF
- 04 | AOF日志:宕机了,Redis如何避免数据丢失?
Redis基础篇(三)持久化:AOF日志的更多相关文章
- Redis持久化——AOF日志
最新:Redis内存--内存消耗(内存都去哪了?) 最新:Redis持久化--如何选择合适的持久化方式 最新:Redis持久化--AOF日志 更多文章... 上一篇文章Redis持久化--内存快照(R ...
- Redis基础(三)Redis持久化:RDB与AOF
什么是Redis持久化? Redis是键值对的内存数据库,它将数据存储在内存里.客户端发送命令到服务器,再由服务器到内存里查找数据. 一旦Redis服务器进程退出,存储在内存里的数据就会丢失. 为了解 ...
- Redis基础篇(四)持久化:内存快照(RDB)
AOF好处是每次执行只需要记录操作命令,记录量不大.但在故障恢复时,需要逐一执行AOF的操作命令,如果日志很大,恢复就很慢. 今天学习另一种持久化方式:内存快照.内存快照,是Redis某一时刻的状态, ...
- Redis基础篇(六)数据同步:主从复制
Redis具有高可靠性,体现在两方面: 一是数据尽量少丢失,通过前面介绍的持久化方式AOF和RDB,在宕机时可以恢复数据. 二是服务尽量少中断,通过副本冗余来实现. 今天我们学习的就是通过主从复制实现 ...
- docker+k8s基础篇三
Docker+K8s基础篇(三) kubernetes上的资源 A:k8s上的常用资源 Pod的配置清单 A:Pod上的清单定义 B:Pod创建资源的方法 C:spec下其它字段的介绍 Pod的生命周 ...
- NIO相关基础篇三
转载请注明原创出处,谢谢! 说在前面 上篇NIO相关基础篇二,主要介绍了文件锁.以及比较关键的Selector,本篇继续NIO相关话题内容,主要谈谈一些Linux 网络 I/O模型.零拷贝等一些内容, ...
- Redis(5.0.0)持久化AOF和 RDB 结合源码分析
主要是挖个坑.候补(代码还没看完..) https://github.com/antirez/redis/tree/5.0 一.Redis保存持久化文件 二.Redis启动加载持久化文件 src/se ...
- Hybrid APP基础篇(三)->Hybrid APP之Native和H5页面交互原理
本文已经不维护,新地址: http://www.cnblogs.com/dailc/p/8097598.html 说明 Hybrid模式原生和H5交互原理 目录 前言 参考来源 前置技术要求 楔子 A ...
- Python基础篇(三)_函数及代码复用
Python基础篇_函数及代码复用 函数的定义.使用: 函数的定义:通过保留字def实现. 定义形式:def <函数名>(<参数列表>): <函数体> return ...
随机推荐
- java类,函数传参
1 package 传参练习; 2 //学生姓名组成的数组:指定区间和查找的名字返回此人是否存在(如果存在返回位置否则-1) 3 public class test1 { 4 public stati ...
- 【mq读书笔记】Index索引文件
1.IndexHeader头部,40字节,记录IndexFile的统计信息: begainTimestamp:该索引文件中包含消息的最小存储时间 endTimestamp:该索引文件中包含消息的最大存 ...
- [BUGCASE]前端码案概述
中医有医案之说,程序会出bug,因此想到将自己在项目中遇到的疑难bug记录下来的想法,出于以下目的: 沉淀经验 通过问题学习 训练解决问题的能力 训练文档写作能力 取名:码案(Bug Case). 医 ...
- 第7.12节 可共享的Python类变量
第7.12节 可共享的Python类变量 一. 引言 在上节已经引入介绍了类变量和实例变量,类体中定义的变量为类变量,默认属于类本身,实例变量是实例方法中定义的self对象的变量,对于每个实例都 ...
- Python正则表达式书写容易碰到的陷阱:\W*和\W*?匹配过程遇到的问题
老猿在分析<Python正则表达式\W+和\W*匹配过程的深入分析>中的问题时,想到一个问题,如果"re.split('(\W*)','Hello,world')"的处 ...
- RSA简单实践
RSA公钥文件解密密文的原理分析 前言 最近在学习 RSA 加解密过程中遇到一个这样的难题:假设已知 publickey 公钥文件和加密后的密文 flag ,如何对其密文进行解密,转换成明文~~ 分析 ...
- PageRank 算法-Google 如何给网页排名
公号:码农充电站pro 主页:https://codeshellme.github.io 在互联网早期,随着网络上的网页逐渐增多,如何从海量网页中检索出我们想要的页面,变得非常的重要. 当时著名的雅虎 ...
- 移动端web网页meta设置
<meta charset='utf-8'><!-- 声明文档使用的字符编码 --> <meta http-equiv="X-UA-Compatible&quo ...
- 如何使用交易开拓者(TB)开发数字货币策略
更多精彩内容,欢迎关注公众号:数量技术宅.想要获取本期分享的完整策略代码,请加技术宅微信:sljsz01 为何使用交易开拓者(TB)作为回测工具 交易开拓者(后文以TB简称)是一个支持国内期货市场K线 ...
- 20201207-2 openpyxl 库与模块导入
1-1 import openpyxl # 通过文件路径,打开工作簿 wb1 = openpyxl.load_workbook('./demo_excel.xlsx') # 用 Workbook() ...