| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> Redis AOF日志浅析 -> 正文阅读 |
|
[大数据]Redis AOF日志浅析 |
????????redis之所以很快,是因为数据是存储在内存中的,直接从内存中读取和从磁盘上读取速度是完全不一样的。内存虽然很快,但是也有个不能忽视的问题,一旦服务器宕机,内存中的数据将全部丢失,所以redis数据的持久化是必须要考虑的问题。redis提供了两种持久化的机制,AOF(Append Only File)日志和RDB快照,下面浅析下AOF日志。 先写日志还是先把数据写到内存? redis是先把数据写到内存,然后再记录日志。 为什么要先把数据记录到内存,然后再记录日志?这大概与redis机制有关系,redis针对AOF的写回定义了几种策略(Always,Everysec 和 No)像比如在No写回策略模式下,写回日志的时机是由操作系统决定什么时候写入的。redis写日志时也不会校验语法的合法性,如果先写日志,这样就会可能存在redis中记录的日志是不合法的redis语句的情况。 AOF中记录的内容? 其实AOF里面记录的是Redis收到的每一条命令,这些命令是以文本的形式保存的,redis实现了一套简单的协议,可以看博文。下面看下具体AOF日志文件中存储什么值。以Redis收到如下命令为例 "set testkey? testvalue"命令后记录的日志为例,看下AOF日志的内容
第一行的 “ *3 ” 表示当前命令有三个部分,每个部分都是由 “$ + 数字?” 开头,后面跟着具体的命令、键或者值,“数字” 表示这部分中的命令、键或者值一共有多少个字节,例如 “ $3 set?” 表示这部分有 3 个字节,其实就是 “ set ” 命令。 Redis先写内存再写入AOF日志两个潜在的风险 1、如果Redis执行完写入内存后服务器突然宕机了,日志还没来得及写入AOF日志,此时再重启时使用AOF恢复就会导致还未写入AOF的命令丢失,如果Redis是用作缓存还好,可以重新从数据库加载即可。但是如果Redis是直接用作数据库的话,此时因为命令还没有来得及记录日志,所以就无法用日志进行恢复了。 2、虽然采用写后日志避免了对当前命令的阻塞,但是可能会给下一个操作带来阻塞的风险,因为AOF日志也是再主线程中执行的,如果把日志写入磁盘时,磁盘的写压力比较大,就会导致写很慢,进而导致后续的操作都没法执行。 Redis的三种写回策略 其实也就是对应Redis配置文件中的配置项 appendfsync 的三个可选项。
但是这三种写回策略都无法做到两全其美。 Always:可以做到基本不丢数据,但是它在每一个写命令后都有一个慢速的落盘操作,不可避免地会影响主线程性能; No:?在写完缓冲区后,就可以继续执行后续的命令,但是落盘的时机已经不在 Redis 手中了,只要 AOF 记录没有写回磁盘,一旦宕机对应的数据就丢失了; Everysec:采用一秒写回一次的频率,避免了“同步写回”的性能开销,虽然减少了对系统性能的影响,但是如果发生宕机,上一秒内未落盘的命令操作仍然会丢失。所以,这只能算是,在避免影响主线程性能和避免数据丢失两者间取了个折中。 但是,按照系统的性能需求选定了写回策略,并不是“高枕无忧”了。毕竟,AOF 是以文件的形式在记录接收到的所有写命令。随着接收的写命令越来越多,AOF 文件会越来越大。这也就意味着,我们一定要小心 AOF 文件过大带来的性能问题。这里的“性能问题”,主要在于以下三个方面:
所以,我们就要采取一定的控制手段,这个时候,AOF 重写机制就登场了。 日志文件重写 随着系统的运行,日志文件会越来越大,因为采用AOF方式生成的日志文件是记录redis收到的每一条命令,我觉得这里应该只会存储对值由改变的相关命令。Redis 官网举了一个例子,如果对一个数执行了100次加 1(incr key) 操作,那其实会记录 100 次 incr key 日志文件,但是 key? 经过100 次 incr 操作之后值变为100,其实只需要 记录 一句set key 100 就可以进行恢复了,Redis官网原文如下 不过,虽然AOF重写后,日志文件会缩小,但是要把整个数据库的最新数据的操作日志都写回磁盘,仍然是一个非常耗时的过程,这时,就需要关注另外一个问题了:重写会不会阻塞主线程? AOF重写会阻塞主线程嘛? 重写过程是由后台子进程bgrewriteaof来完成的,这也是避免阻塞主线程,导致数据库性能下降。 Redis版本小于7.0.0时重写过程 重写过程总结为“一个拷贝,两处日志” “一个拷贝”就是指,每次执行重写时,Redis主进程fork出后台的bgrewriteaof子进程。此时fork会把主线程的内存拷贝一份给bgrewriteaof子进程,这里就包含了数据库最新的数据,然后bgrewriteaof子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。 注意:1、fork采用操作系统提供的写实复制(Copy On Write)机制,就是为了避免一次性拷贝大量内存数据给子进程造成的长时间阻塞问题,但fork子进程需要拷贝进程必要的数据结构,其中有一项就是拷贝内存页表(虚拟内存和物理内存的映射索引表),这个拷贝过程会消耗大量CPU资源,拷贝完成之前整个进程是会阻塞的,阻塞时间取决于整个实例的内存大小,实例越大,内存页表越大,fork阻塞时间越久。拷贝内存页表完成后,子进程与父进程指向相同的内存地址空间,也就是说此时虽然产生了子进程,但是并没有申请与父进程相同的内存大小。那什么时候父子进程才会真正内存分离呢?“写实复制”顾名思义,就是在写发生时,才真正拷贝内存真正的数据,这个过程中,父进程也可能会产生阻塞的风险。 “两处日志”又是什么呢?因为主线程未阻塞,仍然可以处理新来的操作。此时,如果有写操作 第一处日志就是指正在使用的 AOF 日志,Redis 会把这个操作写到它的缓冲区。这样一来,即使宕机了,这个 AOF 日志的操作仍然是齐全的,可以用于恢复。 而第二处日志,就是指新的 AOF 重写日志。这个操作也会被写到重写日志的缓冲区。这样,重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,我们就可以用新的 AOF 文件替代旧文件了。 ????????????????????????????????AOF非阻塞重写过程(图来源于极客时间) |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 14:27:45- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |