Redis 网络架构及单线程模型

Redis 网络架构及单线程模型

最近略有闲暇时间,于是对Redis进行了一些学习,学习途径除了官方文档还有Redis源代码,我看的版本是2.8.13,Redis源码总行数不到5W行,不同组件拆分非常细致,阅读起来也很清晰。这篇博客主要介绍我对Redis网络层架构以及线程模型的一些了解,希望能对大家有所帮助。

Redis网络基础架构

网络编程离不开Socket,网络I/O模型最常用的无非是同步阻塞、同步非阻塞、异步阻塞、异步非阻塞,高性能网络服务器最常见的线程模型也就是基于EventLoop模式的单线程模型。我们看看Redis的网络架构是怎么样的:

Redis基础组建结构

这里解释下上图涉及的组件,Redis网络层基础组件主要包括四个部分:

EventLoop事件轮训器,这部分实现在AE里面。

提供Socket句柄事件的多路复用器,这部分分别对于不同平台提供了不同的实现,比如epoll和select可以用于linux平台、kqueue可以用于苹果平台、evpoll可以用于Solaris平台,这里并没有看到iocp,也就是Redis对于Windows支持并不是很好。

包括网络事件处理器实现的networking,这部分主要包括两个重要的今天要讲的事件处理器:acceptTcpHandler和acceptCommonHandler。

处理网络比较底层的部分,比如网络句柄创建、网络的读写等。

Redis单线程模型

要理解Redis的单线程模型,我们先抛出一些问题,当我们有多个客户端同时去跟Redis Server建立连接,之后又同时对某个key进行操作,这个过程中发生了什么呢?会不会有并发问题?

网络初始化

好了,这些问题先丢在这了,我们看看Redis启动初始化的过程中会做什么事情,这里尽量省略了与本文无关的部分:

初始化Redis Server参数,这部分代码通过initServerConfig实现。

初始化Redis Server,这部分代码在initServer里面。

启动事件轮训器。

对,这里我们就把Redis的启动部分简化为三步,跟网络操作有关的主要在第二步和第三步里面,来看看initServer里面发生了什么:

initServer流程

initServer里面首先创建了一个EventLoop,然后监听Server的IP对应的端口号,假设我们监听的是127.0.0.1:3333这个IP:端口对,我们得到的一个Server Socket句柄,最后通过createFileEvent将我们得到的Server Socket句柄和我们关心的网络事件mask注册到EventLoop上面。EventLoop是什么呢,我们看看它的定义:


type def structae EventLoop{

intmaxfd;/* highest file descriptor currently registered */

intsetsize;/* max number of file descriptors tracked */

longlongtimeEventNextId;

time_tlastTime;/* Used to detect system clock skew */

aeFileEvent *events;/* Registered events */

aeFiredEvent *fired;/* Fired events */

aeTimeEvent *timeEventHead;

intstop;

void*apidata;/* This is used for polling API specific data */

aeBeforeSleepProc *beforesleep;

}aeEventLoop;

上面我们关注的主要是两个东西:events和fired。他们分别是两个数组,events用于存放被注册的事件以及相应的句柄,fired用于存放当EventLoop线程从多路复用器轮训到有事件的句柄的时候,EventLoop线程会把它放入fired数组里面,然后处理。

事件注册示意图

我用上面的示意图描述createFileEvent做的事情,就是将Server Socket句柄和关心的事件mask以及当事件产生的时候的事件处理器accptHandler生成一个aeFileEvent注册到EventLoop的events的数组里面,当然在这之前会首先将事件注册到多路复用器上,也就是epoll、kqueue等这些组件上。事件注册完之后需要对多路复用器进行轮训,来分离我们关心切发生的事件,那就是最后一步,启动事件轮询器。

接收网络连接

上面的步骤完成了服务端的网络初始化,而且事件轮询器已经开始工作了,事件轮询器做什么事情呢,就是不断轮训多路复用器,看看之前注册的事件有没有发生,如果有发生,则将会将事件分离出来,放入EventLoop的fired数组中,然后处理这些事件。

很显然,上面注册的事件是客户端建立连接这个事件,因此当有两个客户端同时连接Redis服务器的时候,事件轮询器会从多路复用器上面分离出这个事件,同时调用acceptHandler来处理。acceptHandler做的事情主要是accept客户端的连接,创建socket句柄,然后将socket句柄和读事件注册到EventLoop的events数组里面,不一样的是对于客户端的事件处理器是readQueryClient。

accept客户端连接以及注册客户端连接句柄示意图

上面示意图表示了acceptHandler处理客户端连接,得到句柄之后再将这个句柄注册到多路复用器以及EventLoop上的示意图。之后再同样再处理下一个客户端的连接,这些都是串行的。

事件轮训

上面接收客户端这部分其实都发生在事件轮训的主循环里面:

void ae Main(aeEventLoop *eventLoop){

eventLoop->stop=0;

while(!eventLoop->stop){

if(eventLoop->beforesleep!=NULL)

eventLoop->beforesleep(eventLoop);

aeProcessEvents(eventLoop,AE_ALL_EVENTS);

}

}

Redis会不断的轮训多路复用器,将网络事件分离出来,如果是accept事件,则新接收客户端连接并将其注册到多路复用器以及EventLoop中,如果是查询事件,则通过读取客户端的命令进行相应的处理,这一切都是单线程,顺序的执行的,因此不会发生并发问题。

应用分析

Redis官网对Redis的读写性能测试结果达到10左右,这是非常吸引人的。Redis的单线程的行为主要是对内存的读写,这些操作其实用不了多少时间,因此瓶颈在网络I/O上面,我们一般提供较好的网络环境就可以提升Redis的吞吐量,比如提高网络带宽,除此之外还可以通过合并命令提交批处理请求来代替单条命令一次次请求从而减少网络开销,提高吞吐量。

参考文献

《Redis源码》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容

  • 最近在看 UNIX 网络编程并研究了一下 Redis 的实现,感觉 Redis 的源代码十分适合阅读和分析,其中 ...
    Draveness阅读 10,638评论 8 56
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,103评论 18 139
  • 春,下午,时间变得松松垮垮 像是穿上父亲的大衣 壶里煮着樱桃 像是爱情,按下又浮起 我的云被仔细捏过了 我的情绪慢...
    我是不是蝎大人阅读 106评论 0 0
  • 烟花三月,细雨朦胧,湖面泛起一圈又一圈的涟漪。那散许的回忆许是淌在了江南古典的屋檐上,又或许落在了布满青藤的院墙上...
    橙情阅读 140评论 0 1
  • 发热:1. 发热是指体温超过38度,热退疹出2. 体温不到37.8度不用退热药3. 发热是症状不是疾病,不会烧坏脑...
    RudyHe阅读 1,630评论 0 51