前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《Redis设计与实现》读书笔记(十五) ——Redis AOF持久化原理与实现

《Redis设计与实现》读书笔记(十五) ——Redis AOF持久化原理与实现

作者头像
用户1327360
发布2018-03-07 15:57:46
8960
发布2018-03-07 15:57:46
举报
文章被收录于专栏:决胜机器学习决胜机器学习

《Redis设计与实现》读书笔记(十五) ——Redis AOF持久化原理与实现

(原创内容,转载请注明来源,谢谢)

一、概述

AOF(Append OnFile)是redis另一种持久化的方式,是通过保存redis服务器写操作的命令来记录数据库的变化。即aof不保存键值对数据,而是保存每一个写操作的语句。流程如下图所示:

aof文件是以redis的命令请求协议格式保存,可以直接打开。例如下图:

上述是在0号数据库,执行了set、sadd、rpush三个命令的结果。

redis服务器启动之前,会载入aof文件,使服务器恢复到关闭之前的状态。

二、aof持久化的实现

1、写入

当aof持久化打开后,每执行一个写命令,redis会以协议格式将其追加到服务器aof_buf缓冲区的末尾。结构体如下:

代码语言:javascript
复制
struct redisServer{
sds aof_buf;//aof缓冲区
}

2、同步

redis服务器进程事件就是一个事件循环,这个循环中的文件事件负责接收客户端的命令请求,以及向客户端发送命令回复;时间事件则是执行类似serverCron定时函数。

每次服务器处理文件事件,即将结束时都会调用flushAppendOnlyFile函数,判断是否需要将aof_buf的缓冲区内容写入aof文件。

flushAppendOnlyFile函数的行为由配置文件appendfsync决定,如果是always则表示将aof_buf写入并同步到aof文件;everysec表示写入aof文件,如果距离上次同步超过1秒则也同步,否则不同步;no表示只写入aof,不同步。

上述的同步,指的是强制要求操作系统进行同步。操作系统对于写入磁盘有策略,并不是每次执行写入就直接写入磁盘,而是会先写入内存,在一定时间或者系统正常关闭的情况下,才会将内容写入文件,这样可以减少操作系统的i/o,加快速度。而这样存在风险,如果还没写入文件系统掉电会宕机,则数据会丢失。因此redis根据操作系统提供的强制写入接口,允许用户通过配置文件的方式要求写入aof的时刻。

上述配置的值,直接决定服务器的效率与安全性,当always时,安全性最高,但是效率最低;no时效率最高,安全性最低;everysec居中。系统默认配置是everysec。

三、aof文件载入与还原

读入流程如下:

1)创建一个不带网络链接的伪客户端(fake client)。由于redis命令只能在客户端执行,而载入的时候是逐行读取aof文件,不需要网络链接。因此使用伪客户端可以正常执行aof文件的命令。

2)从aof文件中读取一条redis命令。

3)用伪客户端执行该redis命令。

4)重复步骤2、3,直到所有写命令处理完毕。

流程图如下:

四、aof重写

1、重写过程

随着时间推移,写命令会逐渐堆积,文件越来越大,而且还原速度会越来越慢。如对同一个键,区分多次进行操作,则在aof中也是多行记录来记录,并不是记录最后一次状态。这样效率较低,则需要aof重写。

重写的命令是bgrewriteaof。

redis对aof文件的重写,并不是真的打开aof文件并分析里面的内容,而是根据redis服务器现有的状态来实现的。为了重写aof,redis会直接读取数据库现有的状态,并自动生成相应的写语句。例如有个list里面有一个键是lists,值是a b c d,redis可以直接生成语句lpush lists a b c d。

整个重写过程如下:

1)忽略空数据库,只考虑有键值对的数据库,并调用select命令进入相应的数据库。

2)创建新的aof文件。

3)遍历所有的键,其中忽略已经过期的键。针对不同的键的数据类型,使用不同的方式生成redis写命令,并且会将每个键相应的过期时间也写入。

4)写入完毕后,关闭文件,重写完成。

由于aof文件的生成,只包含还原当前数据库所需的命令,因此不会浪费硬盘空间。

例如:

上述数据库,aof重新的时候,aof文件会生成以下命令:

代码语言:javascript
复制
select 0
rpush alphabet a b c
expireat alphabet 1385877600000
hmset book name ‘Redis in Action’ author ‘Josiah L. Carlson’publisher Manning
expireat book 1388556000000
set message ‘hello world’

如果列表、集合、有序集合、哈希的元素超过redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD常量定义的值,则生成的aof文件不会是一个键一个语句,会用多条语句来处理某个键,避免单条语句执行超出缓冲区。

2、后台重写

redis执行aof重写的过程,会创建一个子进程进行处理,而服务器继续处理客户端的请求。

但是,这样会有一个问题,重新过程如果客户端对键进行操作,则有可能导致新的aof文件与服务器键值对状态不一致。

为了避免此问题,redis设置一个aof重写缓冲区,当在执行aof重写期间,redis完成一个客户端的写请求后,会同时将这个命令发送给aof缓冲区与aof重写缓冲区。如下图所示:

aof重写完成后,会像父进程发送一个信号,父进程接收到信号后,会调用一个信号处理函数,并执行以下工作:

1)将aof重写缓冲区的所有内容重新写入aof文件,使新aof文件与数据库当前状态保持一致。

2)对新的aof文件进行改名,覆盖原aof文件。

在整个aof重写过程中,只有最后的信号处理函数会使服务器主进程阻塞。即将aof重写缓冲区写入aof文件的时候,不处理客户端发送的请求;重命名期间也不处理客户端发送的请求。

五、总结

1、aof文件通过保存修改服务器数据库的写命令请求,来记录服务器的状态。

2、aof文件以redis请求协议格式保存,可以用本文打开。

3、命令请求会先写入aof缓冲区,之后再定期同步到aof文件。

4、appendsync可以设置同步到aof文件的间隔,有立即(always)、每1秒(everysec)、从不(no)三种方式,其安全性逐渐降低,效率逐渐增高。默认采用每1秒同步一次,即everysec。

5、服务器只要载入并重新执行aof文件里面的redis命令,就可以恢复到原来的状态。

6、aof重新会根据当前服务器的数据,生成redis命令,写入新的aof文件,并且会覆盖原aof文件,以减少aof文件的内容,加快恢复速度。

7、在执行bgrewriteaof命令,redis会先创建一个aof重写缓冲区,并创建一个子进程,由子进程进行aof重写的工作,主进程仍处理客户端的请求。在重写过程中,如果客户端发来写命令,除了主进程执行写命令外,还会将该命令写入aof重写缓冲区中。当子进程完成aof重写工作,会给主进程发送一个信号,主进程会调用信号处理函数,在此期间服务器会阻塞,不处理客户端的请求。信号处理函数首先会将aof重写缓冲区的内容写入新的aof文件,接着将新的aof文件重命名为原来的aof文件的名称,并覆盖原来的aof文件。

——written by linhxx 2017.09.05

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-09-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 决胜机器学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档