《Redis源码学习笔记》文章列表
由于图片较大,缩放较为模糊,请双击打开查看原图 ^_^
Redis提供两种持久化方式,RDB和AOF;与RDB不同,AOF可以完整的记录整个数据库,而不像RDB只是数据库某一时刻的快照;
那么AOF模式为什么可以完整的记录整个数据库呢?
原理:在AOF模式下,Redis会把执行过的每一条更新命令记录下来,保存到AOF文件中;当Redis需要恢复数据库数据时,只需要从之前保存的AOF文件中依次读取命令,执行即可 eg.
我们执行了以下命令:
redis 127.0.0.1:6379> set name diaocow
OK
redis 127.0.0.1:6379> lpush country china usa
(integer) 4
这时候在AOF文件中的类容类似下面:
*3\r\n$3\r\nset\r\n$4\r\nname\r\n$7\r\ndiaocow\r\n
*4\r\n$5\r\nlpush\r\n$7\r\ncountry\r\n$5\r\nchina\r\n$3\r\nusa\r\n
看了上面的内容,我想不用我过多解释,你也能大致猜出AOF协议格式,因为它实在太简单明了了
Redis把更新命令记录到AOF文件,分为两个阶段:
阶段1:把更新命令写入aof缓存
def processCommand(cmd, argc, argv):
# 执行命令
call(cmd, argc, argv)
# 该命令变更了键空间并且AOF模式打开
if redisServer.update_key_space and redisServer.aof_state & REDIS_AOF_ON:
feedAppendOnlyFile(cmd, argc, argv)
def feedAppendOnlyFile(cmd, argc, argv):
# 把命令转换成AOF协议格式
aofCmdStr = getAofProtocolStr(cmd, argc, argv)
redisServer.aof_buf.append(aofCmdStr )
# 存在一个子进程正在进行AOF_REWRITE(关于AOF_REWRITE,稍后详说)
if redisServer.aof_child_pid != -1:
redisServer.aof_rewrite_buf_blocks.append(aofCmdStr )
阶段2: 把aof缓存写入文件
当我们开始下一次
事件循环之前,redis会把AOF缓存中的内容写入到文件:
def flushAppendOnlyFile(force):
if len(redisServer.aof_buf) == 0:
return
# 把缓存数据写入文件
if writeByPolicy(force, redisServer.aof_fsync):
write(redisServer.aof_fd, redisServer.aof_buf, len(redisServer.aof_buf))
# 同步数据到硬盘
if fsyncByPolicy(force, redisServer.aof_fsync):
fsync(redisServer.aof_fd)
更多细节请看: aof.c/flushAppendOnlyFile函数 (ps: 这个函数代码看起来比较晦涩)
看到这里,你也许会有两个疑问:
1. 为什么要调用fsync函数,不是已经调用write把数据写入到文件了吗?
2. 伪代码中aof_fsync是什么,它有几种类型?
首先回答问题1,为什么写入文件后,还要调用fsync函数:
大多数unix系统为了减少磁盘IO,采用了“延迟写”技术,也就是说当我们执行完write调用后,数据并不一定立马被写入磁盘(可能还是保留在系统的buffer cache或者page cache中),这样当主机突然断电,这些我们本以为已经写入到磁盘文件的数据可能就会丢失;所以当我们需要确保数据被完整正确的写入磁盘(譬如数据库的持久化),则需要调用同步函数fsync,它会一直阻塞直到数据全部被写入到硬盘
问题2,aof_fysnc是什么:
aof_fsync用来指定flush策略,也就是调用fsync函数的策略,它一共有三种:
a. AOF_FSYNC_NO :每次都会把aof_buf中的内容写入到磁盘,但是不会调用fsync函数;
b. AOF_FSYNC_ALWAYS :每次都会把aof_buf中的内容写入到磁盘,同时调用fsync函数;
c. AOF_FSYNC_EVERYSEC
由于AOF_FSYNC_ALWAYS每次都写入文件都会调用fsync,所以这种flush策略可以保证数据的完整性,缺点就是性能太差(因为fysnc是个同步调用,会阻塞主进程对客户端请求的处理),而AOF_FSYNC_NO由于依赖于操作系统自动sync,因此不能保证数据的完整性;
那有没有一种折中的方式:既能不过分降低系统的性能,又能最大程度上的保证数据的完整性,答案就是:AOF_FSYNC_EVERYSEC,AOF_FSYNC_EVERYSEC的flush策略是:定期(至少1s)去调用fsync,并且该操作是放到一个异步队列中(线程)去执行,因此不会阻塞主进程
AOF模式至此我们已经基本说完,但是随着Redis运行,AOF文件会变得越来越大(在业务高分期增长的更快),原因有两个:
a. AOF协议本身是文本协议,比较占空间;
b. Redis需要记录从开始到现在的所有更新命令;
这两个原因导致了AOF文件容易变得很大,那有什么方式可以优化吗?譬如用户执行了三个命令:lpush name diaocow; lpush name jack; lpush name jobs
AOF文件会记录以下数据:
*3\r\n$5\r\nlpush\r\n$4\r\nname\r\n$7\r\ndiaocow
*3\r\n$5\r\nlpush\r\n$4\r\nname\r\n$4\r\njack
*3\r\n$5\r\nlpush\r\n$4\r\nname\r\n$4\r\njobs
但其实只需要记录一条:lpush name diaocow jack jbos 命令即可:
*5\r\n$5\r\nlpush\r\n$4\r\nname\r\n$7\r\ndiaocow\r\n$4\r\njack\r\n$4\r\njobs
所以当AOF文件达到 REDIS_AOF_REWRITE_MIN_SIZE(1M)时,Redis就会执行AOF_REWRITE来优化AOF文件;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AOF_REWRITE触发条件:
1. 被动: 当AOF文件尺寸超过REDIS_AOF_REWRITE_MIN_SIZE & 达到一定增长比;
2. 主动: 调用BGREWRITEAOF命令;
主动和被动方式的AOF_REWRITE过程基本相同,唯一的区别就是,通过BGREWRITEAOF命令执行的AOF_REWRITE(主动)是在一个子进程中进行,因此它不会阻塞主进程对客户端请求的处理,而被动方式由于是在主进程中进行,所以在AOF_REWRITE过程中redis是无法响应客户端请求的;
下面我就以BGREWRITEAOF命令为例,具体看下AOF_REWRITE过程:
整个AOF_WRITE过程,最重要的一个函数是: rewriteAppendOnlyFile,它主要做了下面事情:
a. 创建一个临时文件temp-rewriteaof-pid.aof;
b. 循环所有数据库,把每一个数据库中的键值对,按照aof协议写入到临时文件;
c. 重命名临时文件;
伪代码:
def rewriteAppendOnlyFile(filename):
# 创建临时文件
tempFile = createTempFile():
# 循环所有数据库
for db in redisServer.dbs:
# 把数据库中的每一个键值对,按照AOF协议写入临时文件
for key, val in db.key_value_pairs():
expired_time = getExpiredTime(key)
# 过滤过期键
if expired_time != -1 and expired_time < now_time:
continue
# 获取键值对应的命令(譬如 string->set,list->lpush)
cmd = getCmdByValueType(val)
# 按照aof协议保存键值对
saveIntoAofProcotol(cmd, key,value, tempFile)
# 若该键关联一个过期时间,并且未超时,则写入该键的过期信息
if expired_time > now_time:
saveIntoAofProcotol("pexpiredat", key, expired_time, tempFile)
# 重命名文件
rename(tempFile, filename)
当AOF_REWRITE过程执行完毕,Redis会用新生成的文件去替换原来的AOF文件,至此我们可以说,现在AOF文件中的内容已经是最精简的了
现在还存在一个问题:如果我们是通过
主动方式去执行AOF_REWRITE,那么在保存AOF文件期间,“键空间”是可能发生变化的(因为主进程没有被阻塞),若直接用新生成的文件去替换原来的AOF文件,就会造成数据的不一致性(丢失在AOF_REWRITE过程中更新的数据)
那redis如何解决这个问题呢? 在文章开头讲AOF模式的时候,我列举了下面一段伪代码:
def processCommand(cmd, argc, argv):
# 执行命令
call(cmd, argc, argv)
# 该命令变更了键空间并且AOF模式打开
if redisServer.update_key_space and redisServer.aof_state & REDIS_AOF_ON:
feedAppendOnlyFile(cmd, argc, argv)
def feedAppendOnlyFile(cmd, argc, argv):
# 把命令转换成AOF协议格式
aofCmdStr = getAofProtocolStr(cmd, argc, argv)
redisServer.aof_buf.append(aofCmdStr )
# 存在一个子进程正在进行AOF_REWRITE
if redisServer.aof_child_pid != -1:
# 把变更命写写到aof重写缓存
redisServer.aof_rewrite_buf_blocks.append(aofCmdStr )
你会发现,如果redis检测到有一个子进程正在进行AOF_REWRITE,那么它会把这期间所有变更命令写到AOF重写缓存(aof_rewrite_buf_blocks),然后当子进程完成AOF_REWRITE后,它会再把AOF重写缓存中的内容追加到新生成文件,这样我们就可以保证数据的一致性,避免刚才说的问题发生;
总结:
1. 了解AOF模式作用及原理
2. 了解AOF重写作用及原理
3. 了解AOF协议
- 大小: 18.1 KB
- 大小: 19.3 KB
分享到:
相关推荐
Redis 安装简单,可以通过源码编译或使用包管理器安装。启动Redis有前台和后台两种方式,后台启动更常见。Redis 可通过`redis-cli`命令行工具进行交互,提供一系列命令用于操作数据库。 2. Redis 数据类型: - **...
在“狂神redis源码笔记”中,我们可以期待学习到Redis的源码分析、内部机制以及如何通过Java进行高效操作。源码分析是深入理解Redis工作原理的关键,有助于开发者优化使用方式或进行定制化开发。 Redis的核心知识点...
Redis是一个开源的、基于内存的数据...总的来说,Redis入门学习笔记详细介绍了Redis的特性、安装、数据类型、使用场景、备份与恢复、性能测试、Python客户端使用等基础知识和技巧,非常适合新手作为入门学习的资料。
Redis支持数据持久化,可以通过RDB(快照)和AOF(追加文件)两种方式来保存数据到硬盘,使得即使在系统崩溃的情况下数据也不会丢失。在配置文件中,可以通过修改不同的配置项来控制持久化的行为。 在安装Redis时,...
本学习笔记将基于提供的压缩包文件,深入探讨Redis的关键特性、工作原理以及常见应用场景。 首先,"深入redis学习(一)--readme and conf.doc"介绍了Redis的安装和配置过程。在配置文件中,我们可以设置服务器的...
Redis 的环境搭建相对简单,可以从官方网站或源码仓库下载最新稳定版本的源码包,例如 Redis 2.0.4。解压后通过 `make` 命令编译,编译完成后会有 `redis-server` 和 `redis-cli` 两个可执行文件。直接运行 `./redis...
### Redis 学习笔记知识点概览 #### 一、Redis 简介及特性 - **Redis**(Remote Dictionary Server)是一种开源的、基于内存的数据结构存储系统,它支持多种数据结构,如字符串(strings)、散列(hashes)、列表...
首先,从官方网站下载最新稳定版的Redis源码或二进制包。在Linux环境下,可以使用编译源码的方式进行安装,涉及到`make`和`make install`等命令。对于Windows用户,可直接下载预编译的二进制包,解压后配置环境变量...
本文将基于提供的“Redis学习笔记1”内容,详细介绍Redis的安装、启动、单线程特性、发布订阅机制、持久化策略以及AOF和RDB的区别。 1. **Redis安装与启动** Redis的安装通常涉及下载源码包、解压、编译和安装。在...
### Redis学习笔记整理 #### 一、Redis环境搭建 ##### 1.1 简介 Redis是一款开源的键值(Key-Value)型数据库系统,因其高性能和丰富的数据结构而广受欢迎。它不仅可以作为数据库使用,还可以作为一种数据结构服务器...
这份2022年的Redis学习笔记涵盖了Redis的基础概念、核心特性、使用场景以及最佳实践。 一、Redis简介 Redis是一个开源(BSD许可)的,非关系型、内存中的数据结构存储系统,可以用作数据库、缓存和消息中间件。它...
### Redis基础配置笔记 #### 一、Redis简介 Redis 是一款开源且采用 BSD 许可证的高级键值存储系统。由于它支持多种数据结构,如字符串(Strings)、哈希(Hashes)、列表(Lists)、集合(Sets)以及有序集合...
Redis是一款高性能的键值对数据库,它以内存存储为主,数据持久...通过阅读本学习笔记和源码分析,你可以深入了解Redis的工作原理,掌握如何在实际项目中高效地使用Redis。不断实践和探索,你将成为Redis的熟练驾驭者。
在"Redis.zip学习笔记"中,我们可以预期包含以下几个主要的知识点: 1. Redis简介:Redis是一个开源(BSD许可),内存中的数据结构存储系统,它可以用作数据库、缓存和消息代理。它支持多种数据结构,如字符串、...
Redis 是一个高性能的键值对数据库,常被用于数据缓存、消息队列以及数据库功能。...同时,不断学习和实践 Redis 的高级特性,如事务、持久化策略、集群等,将有助于提升你的数据库管理和应用开发能力。
本手册详细整理了Redis的学习过程,包括基础概念、安装部署和实战应用。 一、Redis基础知识 Redis是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它的数据模型包括字符...