• epoll/IOCP/kqueue新模型

  • 非阻塞socket

  • writev代替write/send

  • TCP_CORK/TCP_NOPUSH

epoll/IOCP/kqueue新模型

传统的web服务器用同步socket处理,每一线程服务于一个客户(apache),或者是使用传统的select/poll模型

著名的C10K问题,连接数小的情况,性能也不会很差,随着连接数的上升,性能会直线下降,超过一定数量时,会导致服务器无法提供服务

非阻塞socket

采用新模型更好的处理服务了,为什么还要非阻塞socket?

对于发送数据(调用send),大多数的情况下是不会阻塞的,因为数据是直接放到socket的缓冲里面,只有缓冲满了的情况下会阻塞

已经使用新模型可以检测到该socket能发的时候才发,和阻塞有什么关系?

关键,新模型只能保证发送一次数据不会阻塞,无法检测一次发送多条数据,这个很关键,因为你的数据不可能完整的,如http头和http body可能要分多次包发送

如果一次检测只能发一次,效率会受些影响,用非阻塞socket,一次检测可以一直发送数据,多次调用send,直到发完,或者检测到EAGAIN错误。节省epoll/kqueue系统调用次数,效率大大提升

writev代替write/send

优化了一次检测可以多次发送数据,节省了epoll/kqueue调用了,还不够,能不能做到一次检测,一次发送多条数据,这就是用writev,而不用传统的write/send调用了

可以在调用前构建多条数据数组,又节省几次write/send调用。IOCP的WSASend函数也是可以实现相同的功能

TCP_CORK/TCP_NOPUSH

从socket身上再下功夫,利用linux特有的TCP_CORK和bsd下面的TCP_NOPUSH

http协议层我们可以知道一次请求会发送多少数据给用户,但下面的tcp/ip层无法理解http协议,tcp/ip会按照它的算法,决定是否会合并一些小包发送

能否让tcp/ip也能 理解http协议?

这就是TCP_CORK/TCP_NOPUSH,可以在开始发送http头前设置一下,设置一下socket的TCP_CORK/TCP_NOPUSH,相当于在数据流上加一个塞子,数据不会发送到对方,再发送http其它数据,等这些数据全部发送完了,再把塞子拔掉,取消TCP_CORK/TCP_NOPUSH。节省带宽