最近一边在学习《Redis设计与实现》,一边在研究Redis的源码。正巧学习了Redis单机服务器端设计这一块,感觉受益良多。下面谈一下关于redis的理解。
redis服务器端,本质上就是用C++写的一个后台server程序。Redis服务器将所有的数据库都保存在服务器状态redis.h/redisServer结构的db数组中。每个redisDb结构代表一个数据库,dbnum代表有多少个数据库。
<pre name="code" class="cpp">struct redisServer {
//...
redisDb *db;
int dbnum;
//...
};
struct redisDb {
//...
dict *dict;
dict* expire;
//...
};
然后是redisServer的RDB与AOF两种持久化方法,这个本文先不提。
Redis服务器端是一个单线程的事件驱动程序,服务器端需要处理文件事件和时间事件。
Redis的文本事件处理器是基于Reactor模式开发而成的。文本处理器会通过I/O多路复用(epoll,select等)来同时监听多个套接字,并根据套接字目前的执行任务来为套接字关联不同的事件处理器。当被监听的套接字准备好执行连接应答,读取,写入,关闭等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。但值得注意的一点是,尽管多个文件事件可能会并发的出现,但I/O多路复用的程序总是会将所有产生的事件套接字都放到一个队列里面,然后通过这个队列以有序,同步,每次一个套接字的方式向文件事件分派器传送套接字。
而时间事件又分为定期事件和周期性事件。
服务器将所有的时间事件都放在一个无序链表中,每当时间事件执行器运行时,它就遍历整个链表,查找所有的已到达的时间事件,并调用相应的时间处理器。
可以用下面的python代码来简单表示:
def processTimeEvents():
for time_event in all_time_event():
if time_event.when <= unix_ts_now():
retval = time_event.timeProc()
if retval == AE_NOMORE:
delete_time_event_from_server(time_server)
else:
update_when(time_event, retval)
而redis服务器对于这两种事件的调度策略,是先获取到时间离当前时间最近的时间事件,并计算距离这个时间事件到达还需要多长时间。设这个时间为t,那么接下来服务器就会在最长阻塞时间为t的情况下阻塞并等待文件事件的产生。之后先处理已经产生的文件事件,后处理已经到达的时间事件。
可以用下面的python代码表示:
def aeProcessEvents():
time_event = aeSearchNearestTimer()
remaind_ms = time_event.when - unix_ts_now()
if remaind_ms < 0:
remaind_ms = 0
timeval = create_timeval_with_ms(remaind_ms)
#阻塞并等待
aeApipoll(timeval)
processFileEvents()
processTimeEvents()
一个命令请求从发送到完成主要包括: 1,客户端讲命令请求发送给服务器 。2,服务器读取命令请求,并分析出命令参数。3,命令执行器根据参数查找命令的实现函数,然后执行实现函数并得出命令恢复。4,服务器将命令回复返回 给客户端。
其中服务器从启动的过程包括以下几个过程: 1,初始化服务器状态 与 载入服务器配置。 2,初始化服务器数据结构。 4,还原数据库状态。5,执行事件循环。
所以整个服务器的过程可以由下面的python代码表示。
import sys
import redisServer
redisServer server
def processTimeEvents():
for time_event in all_time_event():
if time_event.when <= unix_ts_now():
retval = time_event.timeProc()
if retval == AE_NOMORE:
delete_time_event_from_server(time_server)
else:
update_when(time_event, retval)
def aeProcessEvents():
time_event = aeSearchNearestTimer()
remaind_ms = time_event.when - unix_ts_now()
if remaind_ms < 0:
remaind_ms = 0
timeval = create_timeval_with_ms(remaind_ms)
#阻塞并等待
aeApipoll(timeval)
#处理文件事件
processFileEvents()
#处理事件事件
processTimeEvents()
def aeMain(eventLoop):
#事件主循环
eventLoop->stop = 0
while (!eventLoop.stop):
if eventLoop.beforesleep != None:
eventLoop.beforesleep(eventLoop)
aeProcessEvents(eventLoop)
if __name__ == '__main__':
#初始化服务器状态
initServerConfig()
#加载配置文件
config()
#设置成守护进程
if (server.daemonize):
daemonize()
#初始化服务器数据结构
initServer()
#还原数据库状态,通过RDB或者AOF
loadDataFromDisk()
#运行事件主循环,知道服务器关闭为止
aeSetBeforeSleepProc(server.el, beforeSleep)
aeMain(server.el)
#服务器关闭,停止循环
aeDeleteEventLoop(server.el)