twemproxy(nutcracker)源代码简要分析
twemproxy(nutcracker)是twitter实现的开源memcached和redis代理,主要功能是根据key分发请求到后端的memcached和redis服务器,简化memcached和redis集群服务的实现。
出于对twemproxy实现机制的好奇,简要阅读了代码,特别是网络处理部分,一般这部分是网络服务器的核心,这里记录下其代码实现逻辑和发现的问题。
twemproxy作为代理服务器,主体逻辑都围绕着数据流转,采用了单线程非阻塞模型,在linux下由epoll驱动整个程序的运行,对于事件驱动模块的封装在event目录下,event_base对象是引擎,conn对象是具体的连接,conn对象中定义一系列事件处理的回调函数,典型的reactor机制,linux下的实现文件是nc_epoll.c 。
事件引擎模块使用了两层回调机制, event_base上有个基本的回调函数,这个回调函数进一步调用conn对象的相应回调函数 (注:一般直接使用conn的回调也就够了)。
面向客户端的conn回调:
twemproxy面向后端时,由server_pool管理各个到后端的conn对象,同样会加入到事件引擎中。
在请求处理模块有2个主要的概念是 mbuf对象和msg对象,mbuf对象是数据缓冲区,发送和接收的数据都存放在mbuf中, 采用链式管理。msg对象是具体的逻辑请求,采用链式管理,形成请求/响应队列。请求和响应的处理模块分别在nc_request.c和nc_response.c中实现。
客户端连接的处理逻辑:
注:从代码实现看回调逻辑的层次性不强,收发数据放入mbuf列表,然后用writev处理,在遇到发送不完时还要拆分mbuf,重新组织iovec,实现上有些复杂。
另外conn对象的数据采用一次读/写完的方式处理,在高压力下可能会产生大量的mbuf对象。
未完待续。
出于对twemproxy实现机制的好奇,简要阅读了代码,特别是网络处理部分,一般这部分是网络服务器的核心,这里记录下其代码实现逻辑和发现的问题。
twemproxy作为代理服务器,主体逻辑都围绕着数据流转,采用了单线程非阻塞模型,在linux下由epoll驱动整个程序的运行,对于事件驱动模块的封装在event目录下,event_base对象是引擎,conn对象是具体的连接,conn对象中定义一系列事件处理的回调函数,典型的reactor机制,linux下的实现文件是nc_epoll.c 。
事件引擎模块使用了两层回调机制, event_base上有个基本的回调函数,这个回调函数进一步调用conn对象的相应回调函数 (注:一般直接使用conn的回调也就够了)。
面向客户端的conn回调:
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回调:
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接收连接,创建客户端conn对象,并将其加入到事件引擎中。
twemproxy面向后端时,由server_pool管理各个到后端的conn对象,同样会加入到事件引擎中。
在请求处理模块有2个主要的概念是 mbuf对象和msg对象,mbuf对象是数据缓冲区,发送和接收的数据都存放在mbuf中, 采用链式管理。msg对象是具体的逻辑请求,采用链式管理,形成请求/响应队列。请求和响应的处理模块分别在nc_request.c和nc_response.c中实现。
客户端连接的处理逻辑:
core_recv
conn->recv 即msg_recv ,read事件处理
conn->recv_next 即req_recv_next ,获得msg对象,没有则创建
msg_recv_chain 创建mbuf对象,接收并处理数据
[create mbuf]
conn_recv 真正的read数据
msg_parse 解析 , mbuf->msg
msg_parsed 解析完成
conn->recv_done 即req_recv_done
req_filter 过滤器,暂无操作
req_forward 分发请求
server_pool_conn 根据key获得后端conn对象
将s_conn加入写事件监控,将msg加入转发队列,可写事件被触发后转发队列内请求
s_conn->enqueue_inq req_server_enqueue_imsgq
conn->recv_next 即req_recv_next,继续下一个
注:从代码实现看回调逻辑的层次性不强,收发数据放入mbuf列表,然后用writev处理,在遇到发送不完时还要拆分mbuf,重新组织iovec,实现上有些复杂。
另外conn对象的数据采用一次读/写完的方式处理,在高压力下可能会产生大量的mbuf对象。
未完待续。