Redis设计与实现第11章 -- AOF持久化 总结(实现 重写)

news2024/11/22 21:27:44

RDB持久化通过保存数据库中的键值对来记录数据库状态的不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态

11.1 AOF持久化的实现

分为命令追加、文件写入和文件同步三个步骤

11.1.1 命令追加

当AOF持久化功能处于打开状态时,服务器在执行完一个写命令后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾
struct redisServer {
    sds aof_buf;//AOF缓冲区 
};

11.1.2 AOF文件的写入和同步

Redis的服务器进程就是一个事件循环loop,这个循环中的文件事件负责接受客户端的命令请求,以及向客户端发送命令请求,而时间事件负责执行向serverCron函数这样的定时任务

服务器每次结束一个事件循环之前,都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区的内容写入和保存到AOF文件里

def eventLoop():
    while True :
        #处理文件事件,接收命令请求以及发送命令回复
        #处理命令请求时可能会有新内容被追加到aof_buf缓冲区中
        processFileEvents()
        #处理时间事件
        processTimeEvents()
        #考虑是否要将 aof_buf中的内容写入和保存到 AOF 文件里面
        flushAppendOnlyFile()

flushAppendOnlyFile函数的行为由服务器配置的appendfsync选项的值来决定,各个不同值产生的行为如下所示

  • always:将aof_buf缓冲区中的所有内容写入并同步到AOF文件
  • everysec:将aof_buf缓冲区的所有内容写入到AOF文件里,如果上次同步AOF文件的事件距离现在超过一秒钟,那么再次对AOF文件进行同步,同步操作由一个专门的线程负责执行
  • no:将aof_buf缓冲区中的所有内容**写入到AOF文件里但是不同步 **

默认值为everysec

AOF持久化的效率和安全性

  • appendfsync = always:效率最慢但是最安全
  • appendfsync = everysec:足够快,最多丢失一秒的数据
  • appendfsync = no:写入速度最快,但是最不安全11.2 AOF文件的载入与数据还原
    服务器只需要读取并重新执行一遍AOF文件里面保存的写命令就可以还原服务器关闭之前的数据库状态
    详细步骤
  1. 创建一个不带网络连接的伪客户端:因为Redis的命令只能在客户端上下文中执行
  2. 从AOF文件里分析并读取一条写命令
  3. 使用伪客户端执行被读取的写命令
    4.一直重复步骤2和3,直到所有的写命令被处理完毕

11.3 AOF重写

随着服务器运行时间的增加,AOF文件里的内容会越来越多,文件的体积也会越来越大,会对Redis服务器甚至宿主机造成影响,而且AOF文件的体积越大,使用AOF文件来进行数据还原所需的时间就越多
因此Redis提供了AOF重写功能,Redis服务器创建了一个新的AOF文件来替代现有的AOF文件,两个文件的AOF保存的数据库状态相同但是新的AOF文件不包含任何浪费空间的冗余命令,所以体积会小

11.3.1 AOF文件重写的实现

这个功能实际上是通过读取服务器当前的数据库状态实现的,比如向list里写入了6条数据,如果写到AOF文件里的话,就是6行数据,但是如果读取list的值,就可以用1行数据实现。
基本原理就是从数据库读取现在键的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令

def aof_rewrite(new_aof_file_name):
    #创建新 AOF 文件
    f=create_file(new_aof_file_name)
    #遍历数据库 
    for db in redisServer.db:
        #忽略空数据库
        if db.is_empty(): 
            continue 
        #写入SELECT命令 指定数据库号码 
        f.write_command("SELECT" + db.id)
        #遍历数据库中的所有键
        for key in db:
            # 忽略已过期的键
            if key.is_expired(): continue
            # 根据键的类型进行重写
            if key.type == string:
                rewrite_string(key)
            elif key.type == List:
                rewrite_list(key)
            elif key.type == Hash:
                rewrite_hash(key)
            elif key.type == Set:
                rewrite_set(key)
            elif key.type == SortedSet:
                rewrite_sorted_set(key)
            #如果键带有过期时间,那么过期时间也要被重写
            if key.have expire time():
                rewrite_expire_time(key)

    #写入完毕 关闭
    f.close()
        
def rewrite_string(key):
    #使用GET命令获取字符串键的值
    value = GET(key)
    #使用SET命令重写字符串键
    f.write_command(SET,key,value)
    
def rewrite list(key):
    #使用LRANGE 命令获取列表键包含的所有元素
    iteml,item2,……itemN=LRANGE(key,0-1)
    #使用RPUSH命令重写列表键
    f.write_command(RPUSH,key,iteml,item2,...itemN)
def rewrite_hash(key):
    #使用HGETALL命令获取哈希键包含的所有键值对
    fieldl,valuel,field2,value2,……fieldN,valueN = HGETALL(key)
    #使用HMSET命令重写哈希键
    f.write_command(HMSET, key,fieldl,valuel,field2,value2,...fieldN,valueN)
def rewrite_set(key):
    #使用SMEMBERS 命令获取集合键包含的所有元素
    eleml,elem2,...elemN = SMEMBERS(key)
    #使用SADD 命令重写集合键
    f.write_command(SADD,key,eleml,elem2,..elemN)
def rewrite_sorted_set(key):
    #使用ZRANGE命令获取有序集合键包含的所有元素
    member1,score1,member2,score2,……,memberN,scoreN = ZRANGE(key,0,-1,"WITHSCORES")
    #使用ZADD命令重写有序集合键
    f.write_command(ZADD,key,score1,member1,score2,member2,……,scoreN,memberN)
    
def rewrite_expire_time(key):
    #获取毫秒精度的键过期时间戳
    timestamp=get_expire_time_in_unixstamp(key)
    #使用PEXPIREAT命令重写键的过期时间
    f.write_command(PEXPIREAT,key,timestamp)
    
        
        
    
    

在实际中,为了避免在执行命令时造成客户端输入缓冲区溢出,重写程序在列表、哈希表、集合、有序集合这四种可能带有多个元素的键时,会先检查键所包含的元素数量,如果元素数量超过了redis.h/REDIS_AOF_REWRITE_ITEMS_PRE_CMD常量的值,程序会用多条命令来记录,而不是单一命令。目前默认值为64

11.3.2 AOF后台重写

Redis如果用主线程处理重写的话,会造成长时间阻塞,所以使用子进程来执行。 子进程在进行AOF重写的时候,服务器进程(父进程)可以继续处理命令请求;子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下保证数据的安全性。 但是要解决的一个问题是,当子进程在进行AOF重写期间,服务器进程还需要继续处理命令请求,而新的命令可能会对现有的数据库状态进行修改,从而使得服务器当前数据库状态和重写后的AOF文件所保存的数据库状态不一致。 为了解决这个问题,Redis服务器设置了一个AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令或,会同时把这个命令发送给AOF缓冲区和AOF重写缓冲区。 这样就可以保证:AOF缓冲区的内容会定期被写入和同步到AOF文件,对现有AOF文件的处理工作也会如常进行;从创建子进程开始,服务器执行的所有写命令都会被记录到AOF缓冲区里,当子进程完成AOF重写工作后,会向父进程发送一个信号,父进程收到信号后,调用信号处理函数并执行以下工作:
  1. 将AOF重写缓冲区的所有内容写入到新AOF文件里
  2. 对新的AOF文件进行改名,原子性地覆盖现有地AOF文件,完成替换

在整个过程里,只有信号处理函数执行时会对服务器进程造成阻塞,对服务器性能的影响降到了最低。

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

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

相关文章

ThinkPHP6门面(Facade)

门面 门面(Facade) 门面为容器中的(动态)类提供了一个静态调用接口,相比于传统的静态方法调用, 带来了更好的可测试性和扩展性,你可以为任何的非静态类库定义一个facade类。 系统已经为大部分…

MySQL win安装 和 pymysql使用示例

目录 一、MySQL安装 下载压缩包: 编写配置文件: 配置环境变量: 初始化服务和账户 关闭mysql开机自启(可选) 建议找一个数据库可视化软件 二、使用pymysql操作数据库 安装pymysql 示例代码 报错处理 一、My…

Parker派克防爆电机在实际应用中的安全性能如何保证?

Parker防爆电机确保在实际应用中的安全性能主要通过以下几个方面来保证: 1.防爆外壳设计:EX系列电机采用强大的防爆外壳,设计遵循严格的防爆标准,能够承受内部可能发生的爆炸而不破损,利用间隙切断原理,防…

空间与单细胞转录组学的整合定位肾损伤中上皮细胞与免疫细胞的相互作用

result 在空间转录组图谱中对人类肾脏进行无监督映射和细胞类型鉴定 我们试图在H&E染色的人类参考肾切除标本组织切片上直接映射转录组特征。该组织来自一名59岁的女性,其肾小球闭塞和间质纤维化程度最低(分别影响不到10%的肾小球或肾实质&#xff…

greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用

简略图 greater<>()(a, b) a > b 返回true&#xff0c;反之返回false less<>()(a, b) a < b 返回true&#xff0c;反之返回false 在cmp中使用&#xff08;正着理解&#xff09; 规则返回true时a在前&#xff0c;反之b在前 在priority_queue中使用 &#xff…

详细描述一下Elasticsearch索引文档的过程?

大家好&#xff0c;我是锋哥。今天分享关于【详细描述一下Elasticsearch索引文档的过程&#xff1f;】面试题。希望对大家有帮助&#xff1b; 详细描述一下Elasticsearch索引文档的过程&#xff1f; Elasticsearch的索引文档过程是其核心功能之一&#xff0c;涉及将数据存储到…

入门车载以太网(6) -- XCP on Ethernet

目录 1.寻址方式 2.数据帧格式 3.特殊指令 4.使用实例 了解了SOME/IP之后&#xff0c;继续来看看车载以太网在汽车标定领域的应用。 在汽车标定领域XCP是非常重要的协议&#xff0c;咱们先来回顾下基础概念。 XCP全称Universal Measurement and Calibration Protocol&a…

Python中常用的函数介绍

Python中常用的几种函数 1、input函数 input()函数&#xff1a;主要作用是让用户输入某个内容并接收它。 #输入你的年龄 >>> age input("my age is :") my age is :20 执行代码后输入年龄&#xff0c;年龄被存放到age变量中&#xff0c;执行print后终端会…

Ubuntu从入门到精通(二)远程和镜像源配置齐全

Ubuntu从入门到精通(二) 1 常见操作配置 1.1 英文语言配置 1.1.1 打开设置 1.1.2 设置语言为英文 1.1.3 重启生效 1.1.4 再次进入,选择更新名字 1.1.5 再次进入,发现已经变成了英文 1.2 输入法配置 1.3 rustdesk安装 1.3.1 Windows系统配置 登陆:https://github.com…

卷积神经网络(CNN)中的池化层(Pooling Layer)

池化层&#xff08;Pooling Layer&#xff09;&#xff0c;也被称为下采样层&#xff0c;是深度学习神经网络中常用的一种层级结构。它通常紧跟在卷积层之后&#xff0c;对卷积层输出的特征图进行下采样操作。 一、定义与功能 池化层的主要作用是通过减少特征图的尺寸来降低计算…

【linux硬件操作系统】计算机硬件常见硬件故障处理

这里写目录标题 一、故障排错的基本原则二、硬件维护注意事项三、关于最小化和还原出厂配置四、常见故障处理及调试五、硬盘相关故障六、硬盘相关故障&#xff1a;硬盘检测问题七、硬盘相关故障&#xff1a;自检硬盘报错八、硬盘相关故障&#xff1a;硬盘亮红灯九、硬盘相关故障…

《操作系统》实验内容 实验二 编程实现进程(线程)同步和互斥(Python 与 PyQt5 实现)

实验内容 实验二 编程实现进程&#xff08;线程&#xff09;同步和互斥 1&#xff0e;实验的目的 &#xff08;1&#xff09;通过编写程序实现进程同步和互斥&#xff0c;使学生掌握有关进程&#xff08;线程&#xff09;同步与互斥的原理&#xff0c;以及解决进程&#xf…

智慧路面管理系统平台 智慧照明 智慧市政 智慧交通

智慧路面管理系统平台   智慧路面管理系统平台&#xff0c;旨在提高城市道路的智能化水平和交通效率。该系统通过集成传感器、摄像头、监控设备、大数据、云计算等多种技术手段&#xff0c;实现对道路状况和交通流量的实时监测与分析&#xff0c;从而提供精准的交通数据和智能…

数据结构 ——— 判断一棵树是否是完全二叉树

目录 满二叉树和完全二叉树示意图 手搓一个完全二叉树 代码实现 满二叉树和完全二叉树示意图 注意区分满二叉树和完全二叉树 满二叉树的每一层都是满的&#xff0c;也就是除了叶子节点&#xff0c;其他节点都有左右节点 完全二叉树的最后一层不一定是满的&#xff0c;但是从…

Vue_Router权限控制:不同角色显示不同路由

写在前面 在Vue中&#xff0c;Router是一个官方提供的用于处理应用程序路由的插件。它允许我们创建单页应用程序&#xff08;SPA&#xff09;&#xff0c;其中不同的页面和组件可以通过URL进行导航和展示。使我们可以轻松地创SPA&#xff0c;并实现可复用和可组合的组件…

java多线程并发执行方法或者调用接口

在开发过程中有时需要检查某个接口或者某个方法是否存在并发安全问题&#xff0c;我们会用到jmeter 、AB 等压测工具辅助我们完成代码测试&#xff0c;虽然这些工具功能很强大&#xff0c;也很好用&#xff0c;但是在开发过程中来使用还是不如直接执行Test 或者main 方法来的方…

Python小游戏28——水果忍者

首先&#xff0c;你需要安装Pygame库。如果你还没有安装&#xff0c;可以使用以下命令进行安装&#xff1a; 【bash】 pip install pygame 《水果忍者》游戏代码&#xff1a; 【python】 import pygame import random import sys # 初始化Pygame pygame.init() # 设置屏幕尺寸 …

测评部署和管理 WordPress 最方便的面板

新版宝塔面板快速搭建WordPress新手教程 - 倚栏听风-Morii - 博客园 初学者使用1Panel面板快速搭建WordPress网站 - 倚栏听风-Morii - 博客园 可以看到&#xff0c;无论是宝塔还是1Panel&#xff0c;部署和管理WordPress都有些繁琐&#xff0c;而且还需要额外去配置Nginx和M…

OpenAI Adjusts Strategy as ‘GPT’ AI Progress Slow

注&#xff1a;本文为两篇关于当前大模型方向讨论的文章。 OpenAI 大改下代大模型方向&#xff0c;scaling law 撞墙&#xff1f;AI 社区炸锅了 机器之心 2024 年 11 月 11 日 11:57 北京 机器之心报道 编辑&#xff1a;Panda、泽南 大模型的 scaling law 到头了&#xff1f…

Java开发者必备:23种设计模式全面解析

文章目录 一、创建型模式1、工厂模式简单工厂工厂方法 2、抽象工厂模式3、原型模式4、建造者模式5、单例模式 二、结构型模式1、适配器模式2、桥接模式3、组合模式4、装饰模式5、外观模式6、享元模式7、代理模式 三、行为型模式1、解释器模式2、模板方法模式3、策略模式4、观察…