服务器端沾包处理的copy效率问题

本文说的基于数据包(有头尾标示并且独立被处理的数据区)的高效通信要求下,阅读需要有一定的沾包处理经验。沾包是tcp流传输的一个特点,形成沾包的主要原因是,数据包小于接收缓冲时,对方不断发生数据包,接受方连续接收数据放入接收缓冲导致的。

要想不产生沾包现像,可以采用一发一答方式,就是我发送一个数据包过去之后,对方应答了再发送下一个数据包;还有就是规定数据包头2个字节(假定)代表数据包长度,每次先接收2个字节,然后根据这两个字节的十六进制值去分配符合数据包大小的缓冲再去接收剩余的数据。这两种方式简化了很多通信数据的处理过程,前者降低服务器负荷,后者增加了OS底层的CPU占用率,两者的效率一样是相当地下的。和采用沾包处理算法的来说,效率根本不是底一个档次这么简单。当然,如果你的系统对单个链接的效率没有过多的要求话另当别论了。另外还有采用固定包(不够长度的填充无效数据)的方式,每次接收缓冲就和固定包大小一致,但这个情况前提是你有足够内存并且浪费带宽。

综上所述,也就是说在效率要求下“沾包处理”是不可避免的了。沾包处理根据服务器角色分有两种情形,一种是网关服务器情形,另一种是逻辑服务器情形。网关服务器的特点是连接量大、单个连接流量小;逻辑服务器特点是连接量少、单个连接流量大。沾包处理需要从流缓冲中找到若干个数据包区域并copy到若干个独立的缓冲中,交予主线程去处理,这个环节重要的工作是copy。假定单线程内存copy是1秒1GByte的效率,这个消耗还是不容忽视的。

单个连接的沾包处理必须有序处理才能保证数据不乱,因为处理一个接收缓冲的时候会有残包的问题,必须留下来和下一个接收缓冲进行合并才能处理提取数据包,也就是说要等前面的人处理完了才能告诉后面的人有没有残包,所以一般都是采用一个线程对一个连接进行沾包处理的工作。

对于网关服务器来说,N个连接就有多个线程来处理,这个似乎还是多线程范畴。对于逻辑服务器,一个网关一般只有一个连接,这个时候就变成了单线程模式了。在单个连接小流量通信情况下,网关服务器总体的copy消耗可能没有太明显的问题,但逻辑服务器因为是单线程的模式,一个连接的流量等于一个网关服务器N个连接的流量总和,这么大流量情况下因为copy导致的效率问题就很明显了(同样在单个连接大流量的情况下,网关服务器也会有同样的问题,只是相对对于当前的用户带宽来说这种可能性小一些罢了)。

那么针对这个问题,假定采用多线程来进行单个连接的沾包处理工作可以进一步提高copy的效率的话,怎么才能保证有序高效的处理呢?目前本人想到的方法如下:

                R1(SR1)                                          R2(SR2)

D1(L1)    D2(L2)     D3.2(L3)          D3.8    D4(L4)     D5(L5)

T1           T2             T3                                   T4             T5

Q1           Q2                                       Q3       Q4             Q5

R:接收缓冲,

SR:接收缓冲的大小

D:接收缓冲包含的数据包内容(假定每个数据包的头两个字节代表长度信息,其中R1包含D1,、D2和D3的20%内容,R2包含D3的80%内容、D4和D5)

L :数据包的长度

T:线程

Q:数据包入列的位置


一、线程T1先唤醒;

二、线程T1根据数据包D1的长度信息L1和SR1比较知道有下一个数据包;

三、线程T1唤醒线程T2并告诉它D2地址是D2=R1+L1,余下缓冲大小是S2=SR1-L1;

四、线程T1进行效验工作并把D1 Copy到队列Q1位置(如果是解密的话,解密处理已经包含了效验和Copy操作了);


五、线程T2根据数据包D2的长度信息L2和S2比较知道有下一个数据包;

六、线程T2唤醒线程T3并告诉它D3地址是D3=D2+L2,余下缓冲大小是S3=S2-L2;

七、线程T2进行效验工作并把D2 Copy到队列Q2位置;


八、线程T3根据数据包D3的长度信息L3和S3比较知道是残包,所以和R2合并得到D3=D3+R2,合并后缓冲大小是S3=S3+SR2;

九、线程T3根据数据包D3的长度信息L3和S3比较知道有下一个数据包;

十、线程T3唤醒线程T4并告诉它D4地址是D4=D3+L3,余下缓冲大小是S4=S3-L3;

十一、线程T3进行效验工作并把D3 Copy到队列Q3位置;


十二、线程T4根据数据包D4的长度信息L4和S4比较知道有下一个数据包;

十三、线程T4唤醒线程T5并告诉它D5地址是D5=D4+L4,余下缓冲大小是S5=S4-L4;

十四、线程T4进行效验工作并把D4 Copy到队列Q4位置;


十五、线程T5根据数据包D5的长度信息L5和S5比较知道是最后一个数据包了;

十六、线程T5进行效验工作并把D5 Copy到队列Q5位置;


十七、主线程依次对Q1~Q5进行有序处理


从上述步骤(四、七、十一、十四、十六)来说,线程T1~T5是可以并行处理效验和Copy工作的。

(抽象了点,慢慢看就会体会理解)






服务器端沾包处理的copy效率问题

上一篇:poj1062


下一篇:Object-C 中的虚函数的学习记录