http://blog.csdn.net/gzh0222/article/details/8523635
1. 实现原理
Nginx 1.1.14版本以前upstream连接建立和获取的机制如下图所示,Nginx会在一开始创建connection pool(进程间不共享,可以避免锁),提供给所有向前/后的连接。
如果要实现upstream长连接,则每个进程需要另外一个connection pool,里面都是长连接。一旦与后端服务器建立连接,则在当前请求连接结束之后不会立即关闭连接,而是把用完的连接保存在一个keepalive connection pool里面,以后每次需要建立向后连接的时候,只需要从这个连接池里面找,如果找到合适的连接的话,就可以直接来用这个连接,不需要重新创建socket或者发起connect()。这样既省下建立连接时在握手的时间消耗,又可以避免TCP连接的slow start。如果在keepalive连接池找不到合适的连接,那就按照原来的步骤重新建立连接。假设连接查找时间可以忽略不计,那么这种方法肯定是有益而无害的(当然,需要少量额外的内存)。
2. 相关配置
Nginx Upstream长连接由upstream模式下的keepalive指令控制,并指定可用于长连接的连接数,配置样例如下:
upstream http_backend {
server 127.0.0.1:8080;
keepalive 16;
}
server {
...
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}
}
目前Nginx只支持反向代理到upstream下配置的server,不支持直接由proxy_pass指令配置的server,更不支持proxy_pass参数中包含变量的情况。此外,为支持长连接,需要配置使用HTTP1.1协议(虽然HTTP 1.0可通过设置Connection请求头为“keep-alive”来实现长连接,但这并不推荐)。
此外,由于HTTPPROXY模块默认会将反向代理请求的connection头部设置成Close,因此这里也需要清除connection头部(清除头部即不发送该头部,在HTTP 1.0中默认为长连接)。
3. 实现细节:(查看转载原文)
3.5. 实现总结
nginx upstream keepalive实现主要通过当解析到upstream模式下的keepalive命令时,为该upstream改变初始化钩子(ngx_http_upstream_init_keepalive),而在初始化upstream时又再次改变初始化对端的钩子(ngx_http_upstream_init_keepalive_peer),在初始化对端时,再一次改变获取对端和释放对端的钩子(ngx_http_upstream_get_keepalive_peer和ngx_http_upstream_free_keepalive_peer)。在获取对端时,会先查找所访问的对端是否已经在cache池内(通过对端的socket地址),如果在cache池内则直接使用cache的连接,否则需要建立新的连接;在释放对端连接时,不直接释放连接,而是将连接保存在cache池中,同时使用对端的socket地址标识该对端,方便后续获取时查找。
可以看到,nginxupstream keepalive在缓存连接(free操作)和获取缓存的连接(get操作)时,只是查找匹配后端服务器的地址,而对前端没有任何感知。这就会造成一个问题,当用户1访问某站点后,会建立一个TCP连接,在后端web服务器没有关闭该连接之前,用户2同样访问该站点时,则不用建立TCP连接即可直接访问,也就是说nginx与后端的keepalive连接对前端来说是共享的,这就造成一个性能问题,当几万个用户同时访问同一站点时,这几万个用户与nginx建立了几万条TCP连接,而nginx与后端服务器确有可能只有一条连接,这一条连接需要服务前端的几万个用户,这就大大的影响了系统的性能!
可以在释放对端连接时添加前端IP地址(获取其他标识信息)来标识前端,在获取连接遍历连接cache池时增加前端IP地址查找匹配,这样方能携带前端标识,避免多个前端共用一个后端连接从而影响性能的问题。
参考文档
http://bollaxu.iteye.com/blog/900424
http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive 官方文档,建议读