作者:finalbsd

Author:FinalBSD
注:有些内容是直接引用相关资料(比如Apache手册)
从2000年开始,FreeBSD就实现了一个功能”Accept Filters”即接收过滤器。

我们看SOCKET编程的模型。

HTTP请求过滤器FreeBSD accf_http) _accf http

  
从这个模型可以看到一旦连接建立,Accpet()会立即返回建立的socket。这样做有几个问题:
1、  也许后面根本没有HTTP请求过来;
2、  请求不完整,属于非法请求;

这样,Apache将派生很多的子进程(假设为prefork模式)去处理这些也许没有用的(可能是SYN FLOOD)连接,最后进程数满,Apache不堪重负。

 FreeBSD实现的接收过滤器明确的延迟了accpet()的返回,只有当满足了一定的条件后,比如一个完整的HTTP/1.0或者HTTP /1.1 HEAD或者GET请求完全被FreeBSD内核缓存之后才返回。HEAD和GET之外的其他请求仍然直接有accpet()进程处理。这样后续的读写 socket操作就不需要等待客户端的请求数据。因此,每个Apache就能处理更多的有效连接。也可以使子进程在accpet()返回后立即处理请求, 因为这个HTTP请求已经建立而且可以read(),这样就减少了Apache进程在执行初始的请求解析(解析HTTP请求)前,执行过多的上下文切换 (Context Switch).  FreeBSD通过accf_http和accf_data(kldload accf_http)来实现接收过滤,Apache相关配置语法为AcceptFilter protocol accept_filter,如

AcceptFilter http httpready
AcceptFilter https dataready

   httpready接收过滤器(Accept Filter)在内核级别缓冲整个HTTP请求。一旦一个请求体被完整接收,内核将把它发送给服务器。因为HTTPS请求已经被加密了,所以只使用了 accf_data(9)过滤器。 注:FreeBSD 6.1必须载入这个模块才能启动Apache2.2,FreeBSD6.2及后续版本不管是否加载这个模块都可以启动Apache,默认不加载,可以在 /etc/rc.conf中加入:apache22_http_accept_enable=”YES”进行启动时自动加载。

Linux上的默认值是:
AcceptFilter http data
AcceptFilter https data

Linux的TCP_DEFER_ACCEPT并不支持对http请求进行缓冲。除none之外的任何值都将在监听程序上启用 TCP_DEFER_ACCEPT 。参见tcp(7)手册页以获得更多详情。使用none将会为那个协议禁用接收过滤器(accept filter)。这对于像nntp这样需要服务器先发送数据的协议很有用处:
AcceptFilter nttp none

NetScaler似乎也使用了同样的思想,只将真正的HTTP请求数据发送给后端服务器,而之前的3次TCP握手都由NetScaler本身处理,大大提升了服务器的吞吐量。