深入理解Redis:命令处理流程
2013-12-15 21:47
225 查看
Redis是著名的NoSQL键值数据库服务器,为了保证效率,其数据都缓存在内存中。与Memcached相比,Redis支持的数据类型更多,包括String,List,Set,Zset和Hash。下面简单介绍一下Redis内部运行流程。
Redis是单线程运行的。在这个主线程中,Redis通过循环不断接收处理外部事件,处理外部事件同时产生的网络操作,如回复客户端请求,也转化为事件进行处理。
Redis的主函数在redis.c文件中,主函数最终调用aeMain函数进入事件处理循环,aeMain即是Redis运行的核心部分。下面详细看一下aeMain函数:
可以看到,这个函数非常简单。每次循环中,Redis都依次调用beforeSleep函数和aeProcessEvents函数。
aeProcessEvents函数是具体处理外部事件的函数,它将会处理外部(也包括内部事件)事件。在调用aeProcessEvents之前,redis都会调用beforeSleep函数。
我们先看看aeProcessEvents函数,它会处理两类事件:定时器事件以及文件(包括网络)相关事件。对应的函数分别是processTimeEvents和readQueryFromClient(其对应接收客户端数据操作,而写操作对应的函数是sendReplyToClient,这两个网络事件相关的函数具体实现在networking.c中)。
具体来看readQueryFromClient,它在接收完客户端数据后,调用processInputBuffer.后续具体流程是:
processInputBuffer->processCommand->call。
其中processCommand会通过lookupCommand函数,查找Redis对应执行的命令,然后调用call函数。Redis支持的命令定义在redis.c的变量redisCommandTable中。
call函数是redid执行命令的核心函数。其中具体执行命令的语句是
c->cmd->proc();//lookupCommand函数查找到的命令处理函数
Redis在本地执行完命令后,如果需要将数据写入AOF文件,或者将数据发送给slave服务器,则调用propagate函数。propagate函数会调用feedAppendOnlyFile和replicationFeedSlaves,通过函数名即能确认两个函数具体功能。
feedAppendOnlyFile函数将命令存入缓存,在本次事件循环结束后,进入下次事件循环之前,redis调用beforeSleep函数时会将缓存写入本地磁盘,具体细节可参考Redis持久化相关介绍。replicationFeedSlaves调用addReply,最终调用aeCreateFileEvent创建一个Socket事件将命令同步到slave.这个事件将在下次事件循环时处理,具体执行的函数将是sendReplyToClient。
现在转回来看c->cmd->proc();以zadd命令为例:
zadd命令对应的函数是zaddCommand,具体实现函数是zaddGenericCommand,其在内存中修改完zset数据(请参考zset实现介绍)后,同样也调用addReply(通过addReplyLongLong)回复客户端,Redis在aeMain的下一次循环时处理对应产生的socket事件。
以上即Redis处理客户端命令的整个过程。需要说明的是,对于每个写操作命令来说,Redis回复客户端之前,将会在内存中更新命令结果,同时可以选择是否同步将命令写入磁盘(可以在beforeSleep函数中会将AOFbuffer写入磁盘,具体参考Redis持久化介绍),然后才会回复客户端,并将命令更新结果同步到slave。
Redis是单线程运行的。在这个主线程中,Redis通过循环不断接收处理外部事件,处理外部事件同时产生的网络操作,如回复客户端请求,也转化为事件进行处理。
Redis的主函数在redis.c文件中,主函数最终调用aeMain函数进入事件处理循环,aeMain即是Redis运行的核心部分。下面详细看一下aeMain函数:
void aeMain(aeEventLoop *eventLoop) { eventLoop->stop= 0; while(!eventLoop->stop) { if(eventLoop->beforesleep != NULL) eventLoop->beforesleep(eventLoop); aeProcessEvents(eventLoop,AE_ALL_EVENTS); } }
可以看到,这个函数非常简单。每次循环中,Redis都依次调用beforeSleep函数和aeProcessEvents函数。
aeProcessEvents函数是具体处理外部事件的函数,它将会处理外部(也包括内部事件)事件。在调用aeProcessEvents之前,redis都会调用beforeSleep函数。
我们先看看aeProcessEvents函数,它会处理两类事件:定时器事件以及文件(包括网络)相关事件。对应的函数分别是processTimeEvents和readQueryFromClient(其对应接收客户端数据操作,而写操作对应的函数是sendReplyToClient,这两个网络事件相关的函数具体实现在networking.c中)。
具体来看readQueryFromClient,它在接收完客户端数据后,调用processInputBuffer.后续具体流程是:
processInputBuffer->processCommand->call。
其中processCommand会通过lookupCommand函数,查找Redis对应执行的命令,然后调用call函数。Redis支持的命令定义在redis.c的变量redisCommandTable中。
call函数是redid执行命令的核心函数。其中具体执行命令的语句是
c->cmd->proc();//lookupCommand函数查找到的命令处理函数
Redis在本地执行完命令后,如果需要将数据写入AOF文件,或者将数据发送给slave服务器,则调用propagate函数。propagate函数会调用feedAppendOnlyFile和replicationFeedSlaves,通过函数名即能确认两个函数具体功能。
feedAppendOnlyFile函数将命令存入缓存,在本次事件循环结束后,进入下次事件循环之前,redis调用beforeSleep函数时会将缓存写入本地磁盘,具体细节可参考Redis持久化相关介绍。replicationFeedSlaves调用addReply,最终调用aeCreateFileEvent创建一个Socket事件将命令同步到slave.这个事件将在下次事件循环时处理,具体执行的函数将是sendReplyToClient。
现在转回来看c->cmd->proc();以zadd命令为例:
zadd命令对应的函数是zaddCommand,具体实现函数是zaddGenericCommand,其在内存中修改完zset数据(请参考zset实现介绍)后,同样也调用addReply(通过addReplyLongLong)回复客户端,Redis在aeMain的下一次循环时处理对应产生的socket事件。
以上即Redis处理客户端命令的整个过程。需要说明的是,对于每个写操作命令来说,Redis回复客户端之前,将会在内存中更新命令结果,同时可以选择是否同步将命令写入磁盘(可以在beforeSleep函数中会将AOFbuffer写入磁盘,具体参考Redis持久化介绍),然后才会回复客户端,并将命令更新结果同步到slave。
相关文章推荐
- 深入理解Redis:命令处理流程
- 深入理解组策略一:组策略处理流程
- [转载]深入理解组策略一:组策略处理流程
- 深入理解组策略一:组策略处理流程
- 深入理解组策略一:组策略处理流程 推荐
- 深入理解Android消息处理系统——Looper、Handler、Thread
- 深入理解计算机系统(3.6)---汇编中精妙的流程控制(重要)(难度较高)
- 深入剖析Redis系列(四) - Redis数据结构与全局命令概述
- 深入理解uboot 2016 - 基础篇(处理器启动流程分析)
- 数字图像处理----深入理解高斯滤波器
- NS2中802.11代码深入理解—packet传输的流程 (转帖)
- 深入理解Activity启动流程
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- 深入理解Android消息处理系统——Looper、Handler、Thread
- 深入理解java异常处理机制
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- redis 个人理解和常用命令以及应用场景
- 104规约超时的理解和报文丢失重发的处理机制深入分析
- 深入理解java异常处理机制
- live555源码分析----SETUP命令处理流程