memcache的執行緒模型
MC採用一master多worker的工作模型,由master負責accept客戶端請求,然後以RR分發給worker;
-t 執行緒數,用於處理請求,預設為4
-b backlog佇列長度,預設1024
-b backlog佇列長度,預設1024
執行緒結構體
- 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 */
- CQ new_conn_queue; /* queue of new connections to handle */
- } LIBEVENT_THREAD;
當master接受新連線後,通過pipe通知worker;
無論是主執行緒還是workers執行緒全部通過libevent管理網路事件,實際上每個執行緒都是一個單獨的libevent例項 ;
啟動流程
程式碼實現
master呼叫accept等待客戶端連線(accept為非阻塞呼叫),返回的sfd也同樣被設定為非阻塞,之後分發給worker;
下面看看dispatch_conn_new內部是如何進行連結分發的。
- void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags,
- int read_buffer_size, enum network_transport transport) {
- CQ_ITEM *item = cqi_new();//建立一個conn_item
- char buf[1];
- int tid = (last_thread + 1) % settings.num_threads;//通過round-robin演算法選擇一個執行緒
-
- LIBEVENT_THREAD *thread = threads + tid;//thread陣列儲存了所有的工作執行緒
-
- cq_push(thread->new_conn_queue, item);//投遞item資訊到Worker執行緒的工作佇列中
-
- buf[0] = 'c';
- //在Worker執行緒的notify_send_fd寫入字元c,表示有連線
- if (write(thread->notify_send_fd, buf, 1) != 1) {
- perror("Writing to thread notify pipe");
- }
worker thread在管道描述符notify_send_fd的回撥函式為thread_libevent_process,故一旦有資料到達立刻執行
//子執行緒會在PIPE管道讀上面建立libevent事件,事件回撥函式是thread_libevent_process
- static void thread_libevent_process(int fd, short which, void *arg) {
- LIBEVENT_THREAD *me = arg;
- CQ_ITEM *item;
- char buf[1];
- if (read(fd, buf, 1) != 1)//PIPE管道讀取一個位元組的資料
- if (settings.verbose > 0)
- fprintf(stderr, "Can't read from libevent pipe\n");
- switch (buf[0]) {
- case 'c'://如果是c,則處理網路連線
- item = cq_pop(me->new_conn_queue);//從連線佇列讀出Master執行緒投遞的訊息 \
-
- if (NULL != item) {
- conn *c = conn_new(item->sfd, item->init_state, item->event_flags,
- item->read_buffer_size, item->transport, me->base);//建立連線
conn_new裡面會建立sfd的網路監聽libevent事件,事件回撥函式為event_handler,而event_handler的執行流程最終會進入到業務處理的狀態機中。
- conn *conn_new(const int sfd, enum conn_states init_state, const int event_flags,
- const int read_buffer_size, enum network_transport transport,
- struct event_base *base)
- {
- conn *c = conn_from_freelist();//獲取一個空閒連線,conn是Memcached內部對網路連線的一個封裝
- if (NULL == c)//如果沒有空閒的連線
- {
- if (!(c = (conn *) calloc(1, sizeof(conn))))//申請空間
- {
- fprintf(stderr, "calloc()\n");
- return NULL;
- }MEMCACHED_CONN_CREATE(c);
- //每個conn都自帶讀入和輸出緩衝區,在進行網路收發資料時,特別方便
- c->rbuf = (char *) malloc((size_t) c->rsize);
- c->wbuf = (char *) malloc((size_t) c->wsize);
- c->ilist = (item **) malloc(sizeof(item *) * c->isize);
- //建立sfd描述符上面的event事件,事件回撥函式為event_handler
- event_set(&c->event, sfd, event_flags, event_handler, (void *) c);
- event_base_set(base, &c->event);
- c->ev_flags = event_flags;
- if (event_add(&c->event, 0) == -1)
- {
- //如果建立libevent事件失敗,將建立的conn新增到空閒列表中
- if (conn_add_to_freelist(c))
- {
- conn_free(c);
- }
- perror("event_add");
- return NULL;
- }
- //libevent事件回撥函式的處理,回撥函式被呼叫時,表明Memcached監聽的埠號有網路事件到了
- void event_handler(const int fd, const short which, void *arg)
- {
- conn *c;
- //進入業務處理狀態機
- drive_machine(c);
執行緒通訊
master和worker通過連線佇列進行單向通訊,即Master接受到新的客戶端連線時,將sfd封裝到conn_queue_item並投送給woker,Worker從其連線佇列中讀取conn_queue_item同客戶端連線進行互動,詳情參見dispatch_conn_new;
- struct conn_queue_item {
- int sfd;//accept之後的描述符
- enum conn_states init_state;//連線的初始狀態
- int event_flags;//libevent標誌
- int read_buffer_size;//讀取資料緩衝區大小
- enum network_transport transport;//內部通訊所用的協議
- CQ_ITEM *next;//用於實現連結串列的指標
- };
-
- struct conn_queue {
- CQ_ITEM *head;//頭指標,注意這裡是單連結串列,不是雙向連結串列
- CQ_ITEM *tail;//尾部指標,
- pthread_mutex_t lock;//鎖
- pthread_cond_t cond;//條件變數
- };
-
- //獲取一個連線
- static CQ_ITEM *cq_pop(CQ *cq) {
- CQ_ITEM *item;
- pthread_mutex_lock(&cq->lock);//執行加鎖操作
- item = cq->head;//獲得頭部指標指向的資料
- if (NULL != item) {
- cq->head = item->next;//更新頭指標資訊
- if (NULL == cq->head)//這裡為空的話,則尾指標也為空,連結串列此時為空
- cq->tail = NULL;
- }
- pthread_mutex_unlock(&cq->lock);//釋放鎖操作
- return item;
- }
參考連結 http://blog.csdn.net/column/details/lc-memcached.html
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15480802/viewspace-1422565/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 執行緒模型執行緒模型
- Dubbo的執行緒模型執行緒模型
- Redis的執行緒模型Redis執行緒模型
- Dubbo執行緒模型執行緒模型
- WPF執行緒模型執行緒模型
- redis執行緒模型Redis執行緒模型
- 程式和執行緒模型執行緒模型
- 03.執行緒模型執行緒模型
- webrtc執行緒模型分析Web執行緒模型
- 淺談Netty的執行緒模型Netty執行緒模型
- Redis執行緒模型的前世今生Redis執行緒模型
- Node.js 的單執行緒事件驅動模型和內建的執行緒池模型Node.js執行緒事件模型
- 深入學習redis 的執行緒模型Redis執行緒模型
- 多執行緒之共享模型執行緒模型
- 執行緒池執行模型原始碼全解析執行緒模型原始碼
- Netty原始碼解析一——執行緒池模型之執行緒池NioEventLoopGroupNetty原始碼執行緒模型OOP
- Redis執行緒模型的原理分析蒼癘Redis執行緒模型
- Java 執行緒記憶體模型Java執行緒記憶體模型
- (三)Redis 執行緒與IO模型Redis執行緒模型
- Redis之單執行緒 Reactor 模型Redis執行緒React模型
- 鴻蒙HarmonyOS實戰-Stage模型(執行緒模型)鴻蒙模型執行緒
- 常用高併發網路執行緒模型設計及mongodb執行緒模型優化實踐執行緒模型MongoDB優化
- 執行緒、開啟執行緒的兩種方式、執行緒下的Join方法、守護執行緒執行緒
- 【雜談】JS相關的執行緒模型整理JS執行緒模型
- 理解微信小程式的雙執行緒模型微信小程式執行緒模型
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- Java多執行緒記憶體模型Java執行緒記憶體模型
- Redis篇:單執行緒I/O模型Redis執行緒模型
- IO流中「執行緒」模型總結執行緒模型
- Dubbo RPC執行緒模型 原始碼分析RPC執行緒模型原始碼
- redis執行緒模型-學習小結Redis執行緒模型
- 伺服器模型——從單執行緒阻塞到多執行緒非阻塞(下)伺服器模型執行緒
- 伺服器模型——從單執行緒阻塞到多執行緒非阻塞(中)伺服器模型執行緒
- java多執行緒:執行緒間通訊——生產者消費者模型Java執行緒模型
- 虛擬執行緒相對於Actor模型或平臺執行緒的主要優勢? - Reddit執行緒模型
- Tomcat執行緒模型 BIO模型原始碼與調優Tomcat執行緒模型原始碼
- Java執行緒篇——執行緒的開啟Java執行緒
- 執行緒池建立執行緒的過程執行緒
- 多執行緒(五)---執行緒的Yield方法執行緒