有关缓冲区使用和自定义TCP服务调整的一些提示?

时间:2010-01-22 17:38:35

标签: networking network-programming tcp buffer

我最近一直在研究一些网络库和框架,例如libevent,libev,Facebook Tornado和Concurrence(Python)。

我在实现中注意到的一件事是使用应用程序级的每个客户端读/写缓冲区(例如Tornado中的IOStream) - 甚至HAProxy都有这样的缓冲区。

除了这些应用程序级缓冲区之外,每个插槽还有OS内核TCP实现的缓冲区。

我可以理解app / lib使用读取缓冲区我认为:app / lib从内核缓冲区读取到app缓冲区,应用程序对数据执行某些操作(例如,对其中的消息进行反序列化)。

但是,我对使用写缓冲区的需要/使用感到困惑。 为什么不写入内核的发送/写入缓冲区?它是为了避免系统调用(写入)的开销吗?我认为当内核通知app / lib套接字是“可写的”时,重点是准备将更多数据推入内核的写缓冲区。 (例如EPOLLOUT)。但是,为什么不放弃应用程序写入缓冲区并将内核的TCP写入缓冲区配置为同样大?

此外,考虑禁用Nagle算法有意义的服务(例如游戏服务器)。在这样的配置中,我想我想要相反:没有内核写缓冲区而是应用程序写缓冲区,是吗?当应用程序准备好发送完整的消息时,它会通过send()等写入应用程序缓冲区,并且内核会通过它。

如果愿意的话,请帮助我清楚了解这些理解。谢谢!

2 个答案:

答案 0 :(得分:1)

嗯,说到haproxy,它在读取和写入缓冲区之间没有区别,缓冲区用于两个目的,这样可以节省副本。但是,做一些改变真的很痛苦。例如,有时您必须重写HTTP标头,并且您必须设法正确地为您的重写移动数据,并保存一些关于前一个标头值的状态。在haproxy中,可以重写连接头,并保存其先前和新状态,因为在重写之后需要它们。使用读取和写入缓冲区,您没有这种复杂性,因为如果您需要任何原始数据,您可以随时回顾读取缓冲区。

Haproxy也能够在Linux上的套接字之间使用拼接。这意味着它不会读取或写入数据,它只是告诉内核在哪里采取什么,以及在哪里移动它。然后内核自动移动指针而不复制数据以将TCP段从网卡传输到另一个(如果可能的话),但数据永远不会传输到用户空间,因此避免了双重复制。

通常,您不需要在缓冲区之间复制数据,这是完全正确的。这是浪费内存带宽。 Haproxy以10Gbps的速度运行,20%的CPU带有拼接,但是没有拼接(2个拷贝),它接近100%。但随后考虑替代方案的复杂性,并做出选择。

希望这有帮助。

答案 1 :(得分:0)

当您使用异步套接字IO操作时,异步读/写操作立即返回,因为异步操作不保证处理所有数据(即将所有必需的数据放入TCP套接字缓冲区或从中获取所有必需的数据) )成功进行一次调用,部分数据必须比多次操作更长久。然后,只要IO操作持续,就需要一个应用程序缓冲区空间来保存数据。