Redis中AOF文件重写与同步

这篇具有很好参考价值的文章主要介绍了Redis中AOF文件重写与同步。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

AOF文件的写入与同步

Redis服务器进程就是一个时间循环(loop),这个循环中的文件时间负责接收客户端的命令请求,以及向客户端发送命令回复,而时间事件则负责执行像serverCron函数这样需要定时运行的函数。因为服务器在处理文件事件时可能会执行些命令,使得一些内容被追加到aof_buf缓冲区里面,所以
在服务器每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,考虑是否将aof_buf缓冲区中的内容写入和保存到AOF文件里面,这个过程可以用以下伪代码表示

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

flushAppendOnlyFile函数的行为由服务器配置的appendfsync选项的值来决定,各个不同的值产生的行为也不同,如果用户没有主动为appendfsync选项设置值,那么appendfsync选项的默认值为everysec

文件的写入和同步

为了提高文件的写入效率,在现代操作系统中,当用户调用write函数,将一些数据写入到文件的时候,操作系统通产会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满,或者超过了指定
的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。这种做法虽然提高了效率,但也为写入数据带来了安全问题,因为如果计算机发生停机,那么保存在内存缓冲区里面的写入数据将会丢失。为此,系统提供
了fsync和fdatasync两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性

AOF持久化的效率和安全性

服务器配置appendfsync选项的值直接决定AOF持久化功能的效率和安全性。

  • 1.当appendfsync的值为always时,服务器在每个事件循环都要讲aof_buf缓冲区中的所有内容写入到AOF文件并且同步AOF文件,所以always的效率时appendfsync选项三个当中最慢的一个,但从安全性来说,always也是最安全的,因为即使出现故障停机,AOF持久化也只会丢失一个事件循环中所产生的命令数据
  • 2.当appendfsync的值为everysec时,服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件并且每隔一秒就要在子线程中对AOF文件进行一次同步。从效率上来讲,everysec模式足够快,并且就算出现故障停机,数据库也只丢失一秒钟的命令数据
  • 3.当appendfsync的值为no时,服务器在每隔事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件,至于何时对AOF文件进行同步,则由操作系统控制。因为处于no模式下的flushAppendOnlyFile调用无须执行同步操作,所以该模式下的AOF文件写入速度总是最快的,不过因为这种模式会在系统缓存中积累一段时间的写入数据,所以该模式的单次同步时长通常是三种模式中时间最长的。从平摊操作的角度来看,no模式和everysec模式的效率类似,当出现故障停机时,使用no模式的服务器将丢失上次同步AOF文件之后的所有写命令数据

例子

  • 例如,对于以下AOF文件来说
*2
$6
SELECT
$1
0
*5
$4
SADD
$6
fruits
$6
banana
$6
cherry
$5
apple
*3
$3
SET
$3
msg
$5
hello
*5
$5
RPUSH
$7
numbers
$3
128
$3
256
$3
512

AOF文件的载入与数据还原

因为AOF文件里面包含了重建数据库状态所需的所有写命令,所以服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态。Redis读取AOF文件并还原数据库状态的详细步骤如下:

  • 1.创建一个不带网络连接的伪客户端(fake client):因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令,伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样。
  • 2.从AOF文件中分析并读取出一条写命令
  • 3.使用伪客户端执行被读出的写命令
  • 4.执行步骤2和步骤3,直到AOF文件中的所有写命令被处理完毕为止
    当完成以上步骤之后,AOF文件所保存的数据库状态就会被万丈地还原出来,整个过程如图
    Redis中AOF文件重写与同步,Redis,redis,数据库,缓存,数据结构
    服务器首先读入并执行SELECT 0命令,之后是SET msg hello命令,在之后是SADD fruits apple banana cherry命令,最后是RPUSH numbers 128 256 512 命令,当这些命令都执行完毕之后,服务器的数据库就被还原到之前的状态了,

整个重写过程可以用以下伪代码表示:

def aof_rewrite(new_aof_file_name):
 # 创建新的AOF文件
 f = create_file(new_aof_file_name)
 # 遍历数据库
 for db in redisServr.db:
  # 忽略空数据
  if db.is_empth(): 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_expir_time(key)
# 写入完毕,关闭文件
f.close()

def rewrite_string(key):
 # 使用GET命令获取字符串键的值
 value = GET(key)
 
 # 使用SET命令重写字符串键
 f.write_command(SET,key,value)
 
def rewrite_list(key):
 # 使用LRANGE命令获取列表键包含的所有元素
 item1, item2, item3, ....itemN = LRANGE(key, 0, -1)
 
 # 使用RPUSH命令重写列表键
 f.write_command(RPUSH, key, item1, item2, item3,...,itemN)
 
def rewrite_hash(key):
 # 使用HGETALL命令后去哈希键包含的所有键值对
 field1, value1, field2, value2, fieldN, valueN = HGETALL(key)
 # 使用HMSET命令重写哈希键
 f.write_command(HMSET, key, field1, value1, field2,value2,...,fieldN, valueN)
 
def rewrite_set(key):
 # 使用SMEMBERS命令获取集合键包含的所有元素
 elem1, elem2, elem3,....,elemN = SMEMBERS(key)
 # 使用SADD命令重写集合键
 f.write_command(SADD, key, elem1, elem2,...elemN)
 
def rewrite_sorted_set(key):
 # 使用ZRANGE命令获取有序集合键包含的新元素
 member1,score1, member2,score2,..., memberN, scoreN = ZRANGE(key, 0, -1, "WOTJSCPRES")
 
 # 使用ZADD命令重写有序集合键
 f.write_command(ZADD, key, score1, memeber1, score2, member2, ...., scoreN, memberN)

def rewrite_expire_time(key):
 # 获取毫秒精度的键过期时间戳
 timestamp = get_expire_time_in_unixstamp(key)
 
 # 使用PEXIREAT命令重写键的过期时间
 f.write_command(PEXIREAT, key, timestamp
)
 

因为aof_rewrite函数生成的AOF文件只包含还原当前数据库状态所必须的命令,所以新AOF文件不会浪费任何硬盘空间

AOF文件重写的实现

虽然Redis将生成新AOF文件替换旧AOF文件的功能命名为"AOF文件重写",但实际上,AOF文件重写并不需要对现有的AOF文件进行任何读取、分析或者写入操作,这个功能是通过读取服务器当前的数据库状态来实现的。

例子

  • 举个例子,如果对服务器对list键执行了以下命令:
127.0.0.1:6379> RPUSH list "A" "B" // ["A", "B"]
(integer) 2
127.0.0.1:6379> RPUSH list "C" // ["A", "B", "C"]
(integer) 3
127.0.0.1:6379> RPUSH list "D" "E" // ["A", "B", "C", "D", "E"]
(integer) 5
127.0.0.1:6379> LPOP list // ["B", "C", "D", "E"]
"A"
127.0.0.1:6379> LPOP list // ["C", "D", "E"]
"B"
127.0.0.1:6379> RPUSH list "F" "G" // ["C", "D", "E", "F", "G"]
(integer) 5

那么服务器为了保存当前list键的状态,必须在AOF文件中写入六条命令。
如果服务器想要用尽量少的命令来记录list键的状态,那么最简单高效的办法不是去读取和分析现有的AOF文件的内容,而是直接从数据库中读取键list的值,然后用一条RPUSH list “C” “D” “E” “F” "G"命令来代替保存在AOF文件中的六条命令这样旧可以将保存list键所需的命令从六条减少为一条了文章来源地址https://www.toymoban.com/news/detail-844012.html

到了这里,关于Redis中AOF文件重写与同步的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 十万字图文详解mysql、redis、kafka、elasticsearch(ES)多源异构不同种类数据库集成、数据共享、数据同步、不同中间件技术实现与方案,如何构建数据仓库、数据湖、数仓一体化?

    数据库大数据量、高并发、高可用解决方案,十万字图文详解mysql、redis、kafka、elasticsearch(ES)多源异构不同种类数据库集成、数据共享、数据同步、不同中间件技术实现与方案,如何构建数据仓库、数据湖、数仓一体化?Delta Lake、Apache Hudi和Apache Iceberg数仓一体化技术架构

    2024年02月07日
    浏览(51)
  • 【redis】通过配置文件简述redis的rdb和aof

    redis的持久化方式有2种,rdb,即通过快照的方式将全量数据以二进制记录在磁盘中,aof,仅追加文件,将增量的写命令追加在aof文件中。在恢复的时候,rdb要更快,但是会丢失一部分数据。aof丢失数据极少,但是恢复数据很慢。redis默认使用rdb进行持久化。 下面结合配置文件

    2024年02月14日
    浏览(42)
  • 【Redis】内存数据库Redis进阶(Redis哨兵集群)

    基于 Redis 集群解决单机 Redis 存在的四大问题:   搭建一个三节点形成的 Sentinel 集群,来监管 Redis 主从集群。   【Redis】内存数据库Redis进阶(Redis主从集群)   架构图: 三个sentinel实例信息: 节点 IP PORT s1 192.168.150.101 27001 s2 192.168.150.101 27002 s3 192.168.150.101 27003 之前

    2024年02月14日
    浏览(43)
  • 【100天精通python】Day44:python网络爬虫开发_爬虫基础(爬虫数据存储:基本文件存储,MySQL,NoSQL:MongDB,Redis 数据库存储+实战代码)

    目录 1 数据存储 1.1 爬虫存储:基本文件存储 1.2 爬虫存储:使用MySQL 数据库 1.3 爬虫 NoSQL 数据库使用 1.3.1 MongoDB 简介

    2024年02月11日
    浏览(69)
  • Redis内存数据库

    Redis内存数据库 NoSQL数据库简介 Redis简介 Redis应用场景 windows下安装和使用Redis 在linux下安装redis Redis数据可视化RedisDesktopManager Redis配置 Redis 数据类型 Redis 字符串(String) Redis 哈希(Hash) Redis 列表(List) Redis 集合(Set) Redis 有序集合(sorted set) Redis key命令 Redis连接命令 Redis服务器命令

    2024年02月09日
    浏览(39)
  • Redis缓存数据库

    目录 一、概述 1、Redis  2、Redis的安装 Redis Windows环境设置 3、String: 字符串 3.1、字符串 3.2、数值 3.3、bitmap 4、Hash: 散列 5、List: 列表 6、Set: 集合 7、Sorted Set: 有序集合 常识: 磁盘:1.寻址:ms(毫秒)2.带宽:MB/s 内存:1.寻址:ns    (纳秒) 2.带宽:GB/s 秒--毫秒--微妙--纳秒

    2024年02月04日
    浏览(57)
  • 1 - 搭建Redis数据库服务器|LNP+Redis

    数据库服务软件分为2类: 关系型数据库服务软件 简称 RDBMS 按照预先设置的组织结构 将数据存储在物理介质上 数据之间可以做关联操作 非关系型数据库服务软件 简称 NoSQL 不仅仅是SQL 不需要预先定义数据存储结构 每条记录可以有不同的数据类型和字段个数 只需要 key valu

    2024年01月25日
    浏览(57)
  • 126、高频Redis面试题:如何保证Redis和数据库数据一致性

    问题:如果数据库中的某条数据放入缓存后,又马上被更新了,那我们应该如何更新缓存 缺点: 如果先更新缓存成功,在更新数据库的时候失败,这时候会导致数据不一致;缓存的作用是不是临时将我们数据保存在内存,便于提高查询速度;但是如果某条数据在数据库中都

    2024年02月13日
    浏览(40)
  • Redis缓存数据库(四)

    目录 一、概述 1、Redis Sentinel 1.1、docker配置Redis Sentinel环境 2、Redis存储方案 2.1、哈希链 2.2、哈希环 3、Redis分区(Partitioning)  4、Redis面试题 Redis Sentinel为Redis提供了 高可用解决方案 。实际上这意味着使用Sentinel可以部署一套Redis, 在没有人为干预的情况下去应付各种各样的失

    2024年02月05日
    浏览(53)
  • Redis 数据库高可用

    (1)在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。 (2)在Redis中,保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展、数据安全不会丢失等。 实现高可用的技

    2024年02月15日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包