twemproxy(nutcracker)是twitter實現(xiàn)的開源memcached和redis代理,主要功能是根據(jù)key分發(fā)請求到后端的memcached和redis服務(wù)器,簡化memcached和redis集群服務(wù)的實現(xiàn)。
出于對twemproxy實現(xiàn)機制的好奇,簡要閱讀了代碼,特別是網(wǎng)絡(luò)處理部分,一般這部分是網(wǎng)絡(luò)服務(wù)器的核心,這里記錄下其代碼實現(xiàn)邏輯和發(fā)現(xiàn)的問題。
twemproxy作為代理服務(wù)器,主體邏輯都圍繞著數(shù)據(jù)流轉(zhuǎn),采用了單線程非阻塞模型,在linux下由epoll驅(qū)動整個程序的運行,對于事件驅(qū)動模塊的封裝在event目錄下,event_base對象是引擎,conn對象是具體的連接,conn對象中定義一系列事件處理的回調(diào)函數(shù),典型的reactor機制,linux下的實現(xiàn)文件是nc_epoll.c 。
事件引擎模塊使用了兩層回調(diào)機制, event_base上有個基本的回調(diào)函數(shù),這個回調(diào)函數(shù)進一步調(diào)用conn對象的相應(yīng)回調(diào)函數(shù) (注:一般直接使用conn的回調(diào)也就夠了)。
面向客戶端的conn回調(diào):
conn->recv = msg_recv;
conn->recv_next = req_recv_next;
conn->recv_done = req_recv_done;
conn->send = msg_send;
conn->send_next = rsp_send_next;
conn->send_done = rsp_send_done;
conn->close = client_close;
conn->active = client_active;
conn->enqueue_outq = req_client_enqueue_omsgq;
conn->dequeue_outq = req_client_dequeue_omsgq;
面向后端memcached和redis的conn回調(diào):
conn->recv = msg_recv;
conn->recv_next = rsp_recv_next;
conn->recv_done = rsp_recv_done;
conn->send = msg_send;
conn->send_next = req_send_next;
conn->send_done = req_send_done;
conn->close = server_close;
conn->active = server_active;
conn->enqueue_inq = req_server_enqueue_imsgq;
conn->dequeue_inq = req_server_dequeue_imsgq;
conn->enqueue_outq = req_server_enqueue_omsgq;
conn->dequeue_outq = req_server_dequeue_omsgq;
twemproxy面向客戶端時,由proxy_accept接收連接,創(chuàng)建客戶端conn對象,并將其加入到事件引擎中。
twemproxy面向后端時,由server_pool管理各個到后端的conn對象,同樣會加入到事件引擎中。
在請求處理模塊有2個主要的概念是 mbuf對象和msg對象,mbuf對象是數(shù)據(jù)緩沖區(qū),發(fā)送和接收的數(shù)據(jù)都存放在mbuf中, 采用鏈式管理。msg對象是具體的邏輯請求,采用鏈式管理,形成請求/響應(yīng)隊列。請求和響應(yīng)的處理模塊分別在nc_request.c和nc_response.c中實現(xiàn)。
客戶端連接的處理邏輯:
core_recv
conn->recv 即msg_recv ,read事件處理
conn->recv_next 即req_recv_next ,獲得msg對象,沒有則創(chuàng)建
msg_recv_chain 創(chuàng)建mbuf對象,接收并處理數(shù)據(jù)
[create mbuf]
conn_recv 真正的read數(shù)據(jù)
msg_parse 解析 , mbuf->msg
msg_parsed 解析完成
conn->recv_done 即req_recv_done
req_filter 過濾器,暫無操作
req_forward 分發(fā)請求
server_pool_conn 根據(jù)key獲得后端conn對象
將s_conn加入寫事件監(jiān)控,將msg加入轉(zhuǎn)發(fā)隊列,可寫事件被觸發(fā)后轉(zhuǎn)發(fā)隊列內(nèi)請求
s_conn->enqueue_inq req_server_enqueue_imsgq
conn->recv_next 即req_recv_next,繼續(xù)下一個
注:從代碼實現(xiàn)看回調(diào)邏輯的層次性不強,收發(fā)數(shù)據(jù)放入mbuf列表,然后用writev處理,在遇到發(fā)送不完時還要拆分mbuf,重新組織iovec,實現(xiàn)上有些復(fù)雜。
另外conn對象的數(shù)據(jù)采用一次讀/寫完的方式處理,在高壓力下可能會產(chǎn)生大量的mbuf對象。
未完待續(xù)。