nc_connection.c

很赞的注释:

*                   nc_connection.[ch]
*                Connection (struct conn)
*                 +         +          +
*                 |         |          |
*                 |       Proxy        |
*                 |     nc_proxy.[ch]  |
*                 /                    \
*              Client                Server
*           nc_client.[ch]         nc_server.[ch]

messsage.c

*            nc_message.[ch]
*        _message (struct msg)
*            +        +            .
*            |        |            .
*            /        \            .
*         Request    Response      .../ nc_mbuf.[ch]  (mesage buffers)
*      nc_request.c  nc_response.c .../ nc_memcache.c; nc_redis.c (_message parser)* Messages in nutcracker are manipulated by a chain of processing handlers,
* where each handler is responsible for taking the input and producing an
* output for the next handler in the chain. This mechanism of processing
* loosely conforms to the standard chain-of-responsibility design pattern*             Client+             Proxy           Server+
*                              (nutcracker)
*                                   .
*       msg_recv {read event}       .       msg_recv {read event}
*         +                         .                         +
*         |                         .                         |
*         \                         .                         /
*         req_recv_next             .             rsp_recv_next
*           +                       .                       +
*           |                       .                       |       Rsp
*           req_recv_done           .           rsp_recv_done      <===
*             +                     .                     +
*             |                     .                     |
*    Req      \                     .                     /
*    ===>     req_filter*           .           *rsp_filter
*               +                   .                   +
*               |                   .                   |
*               \                   .                   /
*               req_forward-//  (1) . (3)  \\-rsp_forward
*                                   .
*                                   .
*       msg_send {write event}      .      msg_send {write event}
*         +                         .                         +
*         |                         .                         |
*    Rsp' \                         .                         /     Req'
*   <===  rsp_send_next             .             req_send_next     ===>
*           +                       .                       +
*           |                       .                       |
*           \                       .                       /
*           rsp_send_done-//    (4) . (2)    //-req_send_done
*
*
* (1) -> (2) -> (3) -> (4) is the normal flow of transaction consisting
* of a single request response, where (1) and (2) handle request from
* client, while (3) and (4) handle the corresponding response from the
* server.

好有爱的注释!!

对应这段注释的代码:

struct conn *
conn_get(void *owner, bool client, bool redis)
{struct conn *conn;conn = _conn_get();conn->client = client ? 1 : 0;if (conn->client) {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->ref = client_ref;conn->unref = client_unref;conn->enqueue_inq = NULL;conn->dequeue_inq = NULL;conn->enqueue_outq = req_client_enqueue_omsgq;conn->dequeue_outq = req_client_dequeue_omsgq;} else {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->ref = server_ref;conn->unref = server_unref;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;}conn->ref(conn, owner);return conn;
}

一个请求被处理的流程

我们按照 messsage.c 里面的4个步骤

后面的图都采用这样的表示方法:

初始状态

考察只有一个后端的情况, 假设有2个client要发送3个请求过来

1.读取请求

此时回调函数:

conn->recv = msg_recv;
conn->recv_next = req_recv_next;
conn->recv_done = req_recv_done;

函数调用栈:

每次发生 req_recv_done(req_forward), 就会调用 req_forward()

req_forward(struct context *ctx, struct conn *c_conn, struct msg *msg)
{if (!msg->noreply) {c_conn->enqueue_outq(ctx, c_conn, msg);}//获得到后端的连接. (可能是新建, 或者从pool里面获取)s_conn = server_pool_conn(ctx, c_conn->owner, key, keylen);s_conn->enqueue_inq(ctx, s_conn, msg);event_add_out(ctx->evb, s_conn);
}

就有一个msg就出现在client_conn->out_q, 同时出现在server_conn->in_q

req_forward用server_pool_conn获得一个server_conn.

2.转发到后端

对于server_conn来说, 因为挂了epoll_out事件, 很快就会调用 conn->send,也就是msg_send.

此时:

conn->send = msg_send;
conn->send_next = req_send_next;
conn->send_done = req_send_done;

调用栈:

#这时, 每次发生 req_send_done, 这个msg就被放到server_conn->out_q

注意, 此时两个msg依然在client_conn->in_q里面

3.接收后端响应

因为server_conn的 epoll_in是一直开着的, 响应很快回来后, 就到了server_conn的 msg_recv 这个过程和调用栈1类似,不过两个函数钩子不一样(图中灰色框)

conn->recv = msg_recv;(和<1>一样)
conn->recv_next = rsp_recv_next;
conn->recv_done = rsp_recv_done;

这里 rsp_recv_next 的作用是, 拿到下一个要接收的msg

rsp_forward 会把 msg从 server_conn->outq 里面摘掉, 同时设置req和resp之间的一一对应关系

//establish msg <-> pmsg (response <-> request) link
pmsg->peer = msg;
msg->peer = pmsg;

上面这个代码是整个过程的精华所在

这时候, client的q_out上排队的req, 就有了对应的response

这时也会设置:

event_add_out(ctx->evb, c_conn);

每收到一个rsp, 就从server_conn的out_q摘掉, 并设置一一对应关系, 如下:

4.把响应回给client

现在每个请求的msg都有了一个对应的response msg, client_conn的out事件也挂上了, 下面这个调用栈:

最终, 一切归于沉寂, 后端连接依然在:

转载于:https://www.cnblogs.com/shenhang/p/4156058.html

twemproxy源码分析之四:处理流程ji(内容属于转载。相关推荐

  1. Storm源码分析之四: Trident源码分析

    Storm源码分析之四: Trident源码分析 @(STORM)[storm] Storm源码分析之四 Trident源码分析 一概述 0小结 1简介 2关键类 1Spout的创建 2spout的消 ...

  2. openxr runtime Monado 源码解析 源码分析:CreateInstance流程(设备系统和合成器系统)Compositor comp_main client compositor

    monado系列文章索引汇总: openxr runtime Monado 源码解析 源码分析:源码编译 准备工作说明 hello_xr解读 openxr runtime Monado 源码解析 源码 ...

  3. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  4. Nginx源码分析:启动流程

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> nginx简介 Nginx的作为服务端软件,表现的主要特点是更快.高扩展.高可靠性.低内存消 ...

  5. Android 音频源码分析——音量调节流程

    源码分析基于android9.0 一.声音类型 对于大多数手机用户来说,操作手机音量按键可以看到,声音类型分为四种:媒体.铃声.闹钟.通话,但是其系统内部则分为十几种类型. 声⾳类型用来区分不同播放用 ...

  6. mosquitto客户端对象“struct mosquitto *mosq”管理下篇(mosquitto2.0.15客户端源码分析之四)

    文章目录 前言 5 设置网络参数 5.1 客户端连接服务器使用的端口号 `mosq->port` 5.2 指定绑定的网络地址 `mosq->bind_address` 5.3 客户端连接服 ...

  7. Spring 源码分析(一) —— 迈向Spring之路(转载)

    看到很好的相关Spring的源码分析专题,就转了,若对作者有影响,请联系我删除该专题文章. 一切都是从Bean开始的 ‍ 在1996年,Java还只是一个新兴的.初出茅庐的编程语言.人们之所以关注她仅 ...

  8. Kubelet源码分析(一):启动流程分析

    源码版本 kubernetes version: v1.3.0 简介 在Kubernetes急群众,在每个Node节点上都会启动一个kubelet服务进程.该进程用于处理Master节点下发到本节点的 ...

  9. MMKV_微信MMKV源码分析(一) | 整体流程

    在使用MMKV框架前,需调用以下方法进行初始化 MMKV.initialize(context); 复制代码 这里的 Java 层主要是获取到保存文件的路径,传入Native层,这里默认的路径是APP ...

最新文章

  1. JavaScript中hoisting(悬置/置顶解析/预解析) 实例解释,全局对象,隐含的全局概念...
  2. 移动端调试利器------微信开源项目
  3. QQ会员2018春节红包抵扣券项目背后的故事
  4. JZOJ 3947 . 【省常中JSOI模拟】收历史作业
  5. 纯css+html实现发光伸缩卡片
  6. C语言必学的12个排序算法:基数排序
  7. 大数据技术之 Kafka (第 3 章 Kafka 架构深入 ) Log存储解析
  8. java 多线程合并结果集_多线程计算数据,然后合并数据
  9. java文件选择器_java中文件选择器JFileChooser的用法
  10. Linux哲学家进餐杀死进程,100分跪求“哲学家就餐问题”在 Linux下运行的源代码(后缀名为.c)!!!...
  11. 第005讲 表单及表单控件,隐藏域
  12. 概率论-数理统计部分思维导图
  13. BLE蓝牙4.0串口调试助手
  14. freemarker ftl java_FreeMarker学习1(Ftl)
  15. es配置中文和拼音分词器
  16. WinPE (老毛桃最终修改版) V09.11 硬盘安装操作系统详细图解
  17. Zemax中控制曲率半径
  18. 威廉.大内的Z理论(1981)--轉載
  19. 小程序关注公众号的方法总结
  20. ros2 for 思岚AI雷达

热门文章

  1. Linux下修改系统时间并写入BIOS
  2. spring-cloud-starter-openfeign使用详解
  3. laravel5.5 尝试使用laravel安装器安装(失败) 最后还是用的composer。。。
  4. 考研笔记-物理层协议
  5. 阿里安全体系获国际顶会表彰,安全技术将有九大新趋势
  6. MySQL:浅析 Impossible WHERE noticed after reading const tables
  7. shrio 权限管理filterChainDefinitions过滤器配置(转)
  8. 用SecureCRT在windows和CentOS间上传下载文件
  9. 常见问题一:Ext.Net的缓存与session值在当前页总是不变
  10. 如何改变maven项目的pom文件中默认的主代码目录 以及默认的测试代码目录?