1.背景
TCP短连接变得越来越普遍,90%以上的TCP流都是小于32KB的,50%的小于4KB。高速处理TCP短连接对于面向用户的在线服务和后台系统都是一项重要的需求,但是Linux TCP的处理速度峰值是30万/s(来源mTCP: A Highly Scalable User-level TCP Stack for Multicore Systems),而packet I/O可以扩展到千万/s,所以当前的Linux TCP架构的处理速度是跟不上实际需求的。
2.MTCP特点
mTCP(User-Level TCP Stack for Multicore System)是一款开源的用户态TCP协议栈。在MTCP看来,原有的Linux内核态TCP/IP栈的实现主要存在以下问题:
- 由于文件的描述符(File Descriptor, FD)在一个进程内部都是共享的,因此不同的CPU核在处理FD的时候存在相关的竞争。这些竞争包括:共享的监听FD的队列(锁保护)、FD的管理、需要在共享的空间内寻找空闲的FD。
- 破坏了应用程序的局部最优原则,比如在基于per-core的包处理队列中,收到中断的CPU和最后实际处理网络数据读写的CPU不是同一个,这就带来大量的系统开销。
- 低效的批处理方式,比如accept/read/write等系统调用效率不高,不断地要进行上下文的切换,并引起cache的不断更新。
- 内核的TCP/IP栈处理报文的时候也很低效,对每个包都要进行内存的分配。
官网链接:mtcp官网
3.MTCP框架
mTCP对TCP报文的处理流程,简要介绍如下。 (1)epoll_server接收到TCP 3次握手的SYN或ACK报文; (2)收发线程将新建的TCP连接的tcb结构加入accept queue; (3)收发线程把报文的有效载荷复制到接收缓存,产生一个 ACK 报文发送到 TXmanager,并为监听线程的Socket生成一个read event; (4)收发线程处理完所有接收的报文后,激活业务线程; (5)业务线程处理事件,并为多条流构建响应报文; (6)业务线程将tcb入队到write queue中; (7)收发线程将需要发送数据的tcb从write queue入队到发送list; (8)收发线程接收待发送报文,并将报文通过对应的队列发送出去。
4.socket API
mctx_t mctx = mtcp_create_context ();
ep_id = mtcp_epoll_create (mctx , N);
mtcp_listen (mctx , listen_id , 4096);
while (1)
{
n= mtcp_epoll_wait (mctx ,ep_id ,events ,N,-1);
for (i = 0; i < n; i++)
{
sockid = events[i]. data.sockid;
if (sockid == listen_id)
{
c = mtcp_accept(mctx , listen_id , NULL);
mtcp_setsock_nonblock (mctx , c);
ev.events = EPOLLIN | EPOLLOUT;
ev.data.sockid = c;
mtcp_epoll_ctl (mctx , ep_id ,
EPOLL_CTL_ADD , c, &ev);
}
else if (events[i]. events == EPOLLIN)
{
r = mtcp_read(mctx , sockid , buf , LEN);
if (r == 0)
mtcp_close(mctx , sockid);
}
else if (events[i]. events == EPOLLOUT)
{
mtcp_write(mctx , sockid , buf , len);
}
}
}
5.参与讨论
|