设为首页 收藏本站
查看: 1052|回复: 0

[经验分享] memcache代码走读:接入模型

[复制链接]
发表于 2015-11-18 09:50:22 | 显示全部楼层 |阅读模式
希望写完这一系列文章,小程们可以对照memcache的源码全部看明白。第一篇文章先将memcache的网络接入,写的很是精彩。 memcache的接入层是依赖与libevent框架的,由其帮助管理I/O多路复用。不过,这里不对libevent做过多的介绍,以后我会陆续写关于libevent的文章,本文重点关注memcache接入层的编程艺术。姑且当libevent是个黑盒子吧。 memcache的接入是由一个主线程和一组worker线程(至少一个线程)协同完成,是一个Master-worker模式。Master负责接入请求,然后指定一个Worker去处理。Worker线程由一个简单的hash算法管理,基本可以理解为循环挨着取线程处理请求,简单的图示: Master通知Worker的方式有点好玩,是通过管道来通知的。这样对于编码来说方便了很多,因为很多细节都交给内核处理,逻辑不用关心太多。 好了,现在梳理一下memcache的各个接入对象。1,线程对象,pthread类型的线程被memcache封装成一个结构,与libevent有机的结合起来。typedef struct {
    pthread_t thread_id;        /* unique ID of this thread */
    struct event_base *base;    /* libevent handle this thread uses */
    struct event notify_event;  /* listen event for notify pipe */
    int notify_receive_fd;      /* receiving end of notify pipe */
    int notify_send_fd;         /* sending end of notify pipe */
    struct thread_stats stats;  /* Stats generated by this thread */
    struct conn_queue *; /* queue of new connections to handle */
    cache_t *suffix_cache;      /* suffix cache */
} LIBEVENT_THREAD;
详细讲一个其中的各个元素,对后续的逻辑的理解很有帮助。thread_id,这个很容易了,线程的唯一IDbase,这是libevent的event_base对象,因为libevent并不是线程安全的,所以每个线程需要维护自己的event,并不能多个线程共用一个。notify_event,上面我们提到,Mater通知Worker是通过管道通知的,Worker接受时间就是这个了nofify_receive_fd,管道的接收端,创建后由上面的base来进行管理notify_send_fd,管道的发送端,会由Master往里写数据stats,统计用的,主要功能以后再说new_conn_queue,Master收到请求后,会把请求打包后挂到一个想通知的Worker负责的列表里面,这就是那个列表指针 Master和Worker的初始化在thread_init里面完成。首先是Master,着重说明的是它的event_base就是全局变量main_base。Worker会执行以下几步:1)创建一个pipe,两端赋给自己的那俩变量。2)初始化自己的event_base。3)将notify_event,receive_fd,和回调函数thread_libevent_process关联起来,当Master通知过来时,这个Worker能够收到数据4)初始化列表指针5)初始化cash指针 2,连接对象memcache将fd封装成一个连接对象,conn这个对象里面的数据比较多,挑几个重点的说一下。int    sfd;,连接的fd
conn_states  state; 描述conn状态的,所有状态的定义都在conn_states 里面
struct event event;
short  ev_flags;
short  which;   /** which events were just triggered */
LIBEVENT_THREAD *thread; 处理它的那个Worker线程指针 3,辅助连接对象上面提到过,Master接收到请求后,会把这个请求打包挂到某一个Worker下面的new_conn_queue下面,这个下面挂的对象是conn_queue_item。里面的变量不具体介绍了,只保留了conn对象的一部分与这个请求相关的一些数据。 现在,结合代码,说一下整个的接入流程(略去了很多写server的通用代码,比如接受参数,守护进程运行,更改limit参数等)。1)首先,Master初始化自己的event_baseL:4588: /* initialize main thread libevent instance */
    main_base = event_init();
2,连接对象(conn)初始化 ,预先分配200个连接对象,即同时可以接受并处理200个客户端的请求L:4594:conn_init(); 3,Master和Worker线程的初始化L:4606 /* start up worker threads if MT mode */
thread_init(settings.num_threads, main_base);
这个函数可以好好看看,里面的具体功能在上面已经讲过了。 4,如果是TCP模式就需要穿件套接字,并监听了。L4665:if (settings.udpport && server_socket(settings.udpport, udp_transport, portnumber_file))这个函数是主要的接入函数,我会详细介绍它。创建完套接字后会进入conn_new ,这个函数是接入层相当重要的一个函数,任何一个新的连接都会由这个函数来处理。它会把刚刚创建的套接字由传进来的event_base来管理。以后Worker收到套接字会与event_handler绑定,当有时间发生时(这里是可读事件),会进入drive_machine函数,也就是memcache的状态机,是接入层与逻辑层的纽带,以后我会专门有文章来讲它,这里只介绍接受请求的逻辑。 Master线程监听了套接字后,当有请求过来时,就能捕获到了,经event_handler->drive_machine->dispatch_conn_new的路径。在dispatch_conn_new这个函数里面会看到主线程会创建一个辅助连接对象conn_queue_item,并把它挂到某个Worker下面。然后往管道写入一个字符,通知管道的另一端Worker,有请求来了。 Worker的event_base会收到请求,进入回调函数thread_libevent_process,把链表中的对象取出来,组成一个新的连接对象conn,这是通过conn_new来处理的,上面Master处理监听套接字时用的就是它,既然这样,我就好好的介绍一下这个函数。 首先,上面我们提到过,连接对象conn初始化时预先分配了200个对象空间,不过有请求来了之后竟然不从这里取用,这是最让我糊涂的地方,那初始化用来干什么呢?所以第一个请求需要重新申请空间。应用到代码中就是先执行conn *c = conn_from_freelist();会返回NULL,然后申请空间:c = (conn *)calloc(1, sizeof(conn)))。另外,conn对象有一个event变量,上面我们提到过。用event_set初始化,与从链表中取出的fd,和回调函数event_handler绑定。L:422, event_set(&c->event, sfd, event_flags, event_handler, (void *)c);L:423, event_base_set(base, &c->event);与该线程的event对象绑定,此后,这个fd就由这个线程的libevent来管理了。当有请求来时,进入event_handler,进而进入状态机。 DSC0000.gif           版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-140603-1-1.html 上篇帖子: Ubuntu14.04下,Tomcat8+Nginx+memcache配置服务器集群session共享 下篇帖子: Linux上完美安装memcache(含自启动)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表