对系统的某个接口进行极限压测,随着并发量上升,nginx开始出现502 no live upstreams while connecting to upstream的报错,维持最大并发量一段时间,发现调用接口一直返回502,即nginx已经发现不了存活的后端了。mysql
经过跟踪端口,发现nginx 跟后端建立了大量的链接。这很明显是没有使用http1.1长链接致使的。所以在upstream中添加keepalive配置。nginx
upstream yyy.xxx.web{ server 36.10.xx.107:9001; server 36.10.xx.108:9001; keepalive 256; } server { ··· location /zzz/ { proxy_pass http://yyy.xxx.web; ··· } }
根据官方文档的说明:该参数开启与上游服务器之间的链接池,其数值为每一个nginx worker能够保持的最大链接数,默认不设置,即nginx做为客户端时keepalive未生效。web
默认状况下 Nginx 访问后端都是用的短链接(HTTP1.0),一个请求来了,Nginx 新开一个端口和后端创建链接,请求结束链接回收。若是配置了http 1.1长链接,那么Nginx会以长链接保持后端的链接,若是并发请求超过了 keepalive 指定的最大链接数,Nginx 会启动新的链接来转发请求,新链接在请求完毕后关闭,并且新创建的链接是长链接。redis
上图是nginx upstream keepalive长链接的实现原理。sql
首先每一个进程须要一个connection pool,里面都是长链接,多进程之间是不须要共享这个链接池的。 一旦与后端服务器创建链接,则在当前请求链接结束以后不会当即关闭链接,而是把用完的链接保存在一个keepalive connection pool里面,之后每次须要创建向后链接的时候,只须要从这个链接池里面找,若是找到合适的链接的话,就能够直接来用这个链接,不须要从新建立socket或者发起connect()。这样既省下创建链接时在握手的时间消耗,又能够避免TCP链接的slow start。若是在keepalive链接池找不到合适的链接,那就按照原来的步骤从新创建链接。 我没有看过nginx在链接池中查找可用链接的代码,可是我本身写过redis,mysqldb的链接池代码,逻辑应该都是同样的。谁用谁pop,用完了再push进去,这样时间才O(1)。 后端
须要注意的是:我在个人nginx1.12.0版本中新增该配置以后,再次压测,502问题依然存在,升级到1.16.0版本以后,502问题解决。缘由是nginx1.12.0版本不支持长链接配置。服务器
另外,若是nginx所在服务器和创建链接后端服务所在服务器不在同一网段时(即两台机器之间存在防火墙),还须要注意防火墙对长链接的影响。并发