redis-server和client连接建立

redis版本

redis6.0+

socket连接建立的要素

  1. 网络连接的建立离不开socket,socket在不同操作系统下有不同的接口,这里以epoll为例。
  2. socket连接建立关键点1:在指定的端口创建监听套接字,并且将该套接字通过epoll_ctl加入epoll_fd中。
  3. 关键点2:定时通过epoll_wait查看是否有连接请求过来,如果有则调用accpet创建client的套接字并且将其加入进程的套接字管理的数据结构中,以便后续查找和管理套接字。
  4. 关键点3:上层业务处理数据异常时,主动关闭下层socket。
  5. 关键点4:连接超时,主动关闭socket。
  6. 关键点5:socket发现对方的关闭请求,把业务层的所有相关数据一并清除并关闭。

redis中上述要素对应的操作

epoll接口封装

redis封装epoll的接口。在文件ae_epoll.c中, 对应关系如下

aeApiCreate   ==> epoll_create
aeApiAddEvent ==> epoll_ctl (EPOLL_CTL_ADD, EPOLL_CTL_MOD)
aeApiDelEvent ==> epoll_ctl(EPOLL_CTL_MOD, EPOLL_CTL_DEL)
aeApiPoll     ==> epoll_wait
接收请求并建立连接
  1. 创建监听套接字,并设置处理函数。在这之前先简要介绍redis的事件驱动框架。redis进程的主线程调用aeMain函数,在while循环中调用aeProcessEvents处理触发的事件。网络事件当然也会在其中被调用,大致框架代码如下:
void aeMian() {
  while (!stop) {
    aeProcessEvents()
  }
}

void aeProcessEvents() {
  events = aeApiPoll()
  for (event in events) {
    if (event.mask & AE_READ) {
      event.read_handler(event)
      }
    if (event.mask & AE_WRITE) {
      event.write_handler(event)
      }
  }
}

每个fd会绑定一个处理函数,当读写事件触发时,调用对应的处理函数。在server.c中,我们可以看到监听套接字绑定的处理函数是acceptTcpHandler.代码大致如下:

void initServer() {
    // ......
    for (j = 0; j < server.ipfd_count; j++) {
        if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
            acceptTcpHandler,NULL) == AE_ERR)
            {
                serverPanic(
                    "Unrecoverable error creating server.ipfd file event.");
            }
    }
    // ......
}

在accept过程中,会创建三个结构体:client, connection, aeFileEvent用于绑定文件描述符fd。最终调用的处理函数是clientAcceptHandler。最后附上调用关系的堆栈图:


accept堆栈调用
连接关闭

首先附上连接关闭时的堆栈截图,由上面的分析可知,连接关闭必然会调用aeApiDelEvent,因此在此断点就可以通过堆栈看到调用关系。


连接关闭调用堆栈图

读者可以去看下#7 beforeSleep中调用freeClientsInAsyncFreeQueue的代码。连接的关闭由主线程执行,并且是异步的关闭,在处理IO事件或者命令时会调用freeClientAsync函数将要关闭的连接加入server.clients_to_close队列中,然后由主线程去关闭。

主动关闭连接

当服务器认为该连接已经无效时,调用freeClientAsync,将该连接加入队列中,稍后统一关闭。这里列举几个可能调用freeClientAsync的地方:写数据失败,读数据失败。

socket读取异常关闭连接

通常在client主动关闭连接或者client出现异常时触发。通过在freeClientAsync设置断点,然后client主动关闭,查看堆栈调用图。


client主动关闭时的调用关系

调用freeClientAsync处的代码截图

由此可知,当client主动关闭连接时,触发读事件,读的数据长度为0,说明连接关闭,则服务器这边也将连接关闭。

client超时时关闭连接

ps:如何找到redis超时关闭连接的调用?断点不是一个好选择,等待的时间太长了。首先通过Google知道redis可配置连接的超时时间,因此现在config.c中找到配置项对应的进程内的变量,搜索该变量被引用的地方,找到了clientsCronHandleTimeout函数,通过断点该函数,找到了调用的堆栈关系图。


client超时关闭调用堆栈图

由调用堆栈图可知,会创建一个定时事件在定时事件中检查连接上次交互的时间是否超过超时时间。(关于定时事件,在后面有机会再详谈)

总结

  1. 异步连接的关闭。好处:a、加快了命令处理的效率,降低延时,可以理解为削峰处理。b、将连接的关闭延后到统一处理,避免了可能存在的并发。
  2. 笔者曾分析过自己项目C++实现的网络底层库,也曾分析过Golang通过epoll实现的网络库。个人的理解是,无论何时,抓住底层的socket接口,就能很好理解上层框架的处理逻辑了。而且这些框架大同小异,归根结底是因为底层接口的性质决定了框架的结构。笔者后续再分析别的源码的网络库时,应该不会再专门写博客了。
  3. gdb断点分析源码是个非常好的手段,先找到最重要调用的底层接口,然后断点查看堆栈调用图,即可快速确定调用关系。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351