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