一次qps测试实践(续)
想着探讨nginx负载均衡的作用
服务器A 4核 B 8核
nginx 部署在A,tomcat1 tomcat2部署在B(因为没第三台机器了,只能先这样看看效果)
nginx worker_connections 51200 后台worker process进程的最大并发链接数 worker_connections 1024; # 并发总数是 worker_processes 和 worker_connections 的乘积
nginx worker_process auto (=4)
nginx 配置长连接 keepalive 1000(每个worker process进程初始长连接数,设置越大,内存占用越多)
tomcat配置
<Connector port="8088" protocol="HTTP/1.1" maxThreads="5" minSpareThreads="2" acceptCount="2" connectionTimeout="1000" maxConnections="1000" keepAliveTimeout="300000" maxKeepAliveRequests="1000" redirectPort="8443" />
关键参数说明:
maxThreads -线程池中最大的活跃线程数,默认值200,不要太高,线程切换有开销 minSpareThreads-保持存活的最小线程数,默认值25 acceptCount -当tomcat起动的线程数达到最大时,接受排队的请求个数。默认值为100,超出的会拒绝请求
maxKeepAliveRequests: 最大长连接个数(1表示禁用,-1表示不限制个数,默认100个。一般设置在100~200之间)nginx动态的转给tomcat,nginx是不能keepalive的(错),而tomcat默认开启keepalive,会等待keepalive的timeout,默认不设置就是使用connectionTimeout。所以必须设置tomcat的超时时间,并关闭tomcat的keepalive。否则会产生大量tomcat的socket timewait。maxKeepAliveRequests="1"表示每个连接只响应一次就关闭,这就不会等待timeout了,可避免tomcat产生大量TIME_WAIT连接,从一定程度上避免tomcat假死。
第一次测试,20并发2分钟,nginx-》B,tps 1500,总事务数 20w,
第二次测试,20并发2分钟,nginx-》2*B,tps 1500
猜测?
1)nginx与tomcat连接太多,导致nginx端口占满后阻塞
2)nginx工作线程满了
3)压力还不够
————————————————————————————
互联网常见架构接口压测性能分析及调优手段建议
https://www.cnblogs.com/dimmacro/p/4849729.html
2.2 压测现象:数据库无压力,应用增加多台后tps不变
2.2.1 问题分析:
1N1T和1N10T的tps一样,都为5000,增大并发时错误数增多,应用cpu耗费70%,db无压力,nginx单台通过ss –s 发现端口占满,即nginx到tomcat之间转发的连接端口time-wait状态6万多。Nginx存在瓶颈。
2.2.2 改进措施:
调优nginx参数,将短连接改为长连接
2.2.3 改进效果:
1N3T的tps能到17376,tomat的cpu压力84%,db的qps18000,cpu69%,应用的资源基本使用到量。
————————————————————————————————————————————
看了这个帖子后,就一直往长连接去靠,查阅了很多资料
————————————————————————————————————————————
记一次压力测试和对nginx/tomcat配置的调整
https://www.cnblogs.com/AloneSword/p/4119928.html
批注:nginx改keepalive ,无果——tomcat keepalive放大
原因个人分析:tomcat默认打开keepalive功能,而其maxKeepAliveRequests参数默认值为100,tomcat只接受100个长连接,假设nginx发了1000个长连接,还有900个长连接tomcat直接当短链接处理,发出关闭信号,进入time_wait状态,nginx只得再开连接
在我们压测的过程中, 通过netstat命令可以看到有很多nginx向tomcat发起的连接。 这些连接都是短连接,每次用完即关闭。于是想到nginx向后端源服务器能否建立长连接的问题。查看了一下文档,nginx从1.1.4版本开始,支持proxy_pass的时候向后端源服务器建立长连接。
通过tcpdump抓包发现, 首先发出 Fin 包的是tomcat。 也就是说, tomcat主动关闭的连接。
原来在tomcat的配置文件中, 有关于keepalive的几个参数。 包括每一个连接完成多少个http请求之后就关闭等。
对tomcat的connector进行了一些调整(包括maxKeepAliveRequests和keepAliveTimeout两个参数,都设置成-1)之后, 再看连接,已经不会频繁断开并重建了。 QPS也提升到了900+.(待验证)
——————————————————————————————
Nginx upstream性能优化
https://www.cnblogs.com/shengs/p/4701905.html
keepalive
批注:keepalive参数表示每个工作进程所能保持的最大长连接,且不会限制连接总数,新长连接会创建
激活对上游服务器的连接进行缓存。connections参数设置每个worker进程与后端服务器保持连接的最大数量。这些保持的连接会被放入缓存。如果连接数大于这个值时,最久未使用的连接会被关闭。需要注意的是,keepalive指令不会限制Nginx进程与上游服务器的连接总数。 新的连接总会按需被创建。connections参数应该稍微设低一点,以便上游服务器也能处理额外新进来的连接。
1) 对于HTTP代理,proxy_http_version指令应该设置为“1.1”,同时“Connection”头的值也应被清空。
2) 另外一种选择是,HTTP/1.0协议的持久连接也可以通过发送“Connection: Keep-Alive”头来实现。不过不建议这样用。
3) 对于FastCGI的服务器,需要设置 fastcgi_keep_conn 指令来让连接keepalive工作。当使用的负载均衡方法不是默认的轮转法时,必须在keepalive 指令之前配置。
——————————————————————————————————————
nginx配置长连接---keepalive相关
http://blog.csdn.net/senlin1202/article/details/54617635
# 批注:连接到上游服务器的最大并发空闲keepalive长连接数(默认是未设置,建议与Tomcat Connector中的maxKeepAliveRequests值一样) # 当这个数被超过时,使用"最近最少使用算法(LUR)"来淘汰并关闭连接。 keepalive 768;
——————————————————————————————————————
关于 Nginx upstream keepalive 的说明
https://www.cnblogs.com/kabi/p/7123354.html
批注(重要):如果并发请求超过keepalive值,nginx启用新连接,且默认发送长连接,后端tomcat收到keepalive信号,不主动关闭,由nginx来发送关闭信号,由此产生nginx 得time-wait状态连接,且占用端口
1. 默认情况下 Nginx 访问后端都是用的短连接(HTTP1.0),一个请求来了,Nginx 新开一个端口和后端建立连接,请求结束连接回收。如果像上面的配置一样设置了长连接,Nginx 会接受客户端的请求,处理完成之后 Nginx 会「继续保持和后端的长连接」,如果并发请求超过了 keepalive 指定的最大连接数,Nginx 会启动新的连接 来转发请求,新连接在请求完毕后关闭,而且新建立的连接是长连接,这可能会造成额外的问题,最后再说。
2. keepalive 指定的 数值 是 Nginx 每个 worker 连接后端的最大长连接数,而不是整个 Nginx 的。 而且这里的后端指的是「所有的后端」,而不是每一个后端(已验证)。
先说一个现象,我发现当 keepalive 设置小的时候,比如1,那么并发请求上去之后 Nginx 会出现大量的 TIME_WAIT,而如果把 keepalive 关掉(proxy_http_version 1.1 和 proxy_set_header Connection “” 指令也去掉),那么 TIME_WAIT 就会出现在后端服务器了,后端用的是 tornado,相信 jetty 和 tomcat 也是一样。(这个现象我亲自验证)
# tcpdump -i em2 -A host 10.0.11.12 -n
看到:
00:22:53.252039 IP 10.0.31.84.53915 > 10.0.11.12.ddi-tcp-1: Flags [P.], seq 81:161, ack 275, win 123, length 80
@.@.].
..T
…..”…p%8|..P..{>…GET / HTTP/1.1
Host: http_backend
User-Agent: ApacheBench/2.3
Accept: */*
但是如果把 pxe1.hy01 的长连接设置都去掉的话,抓包如下:
00:23:58.111974 IP 10.0.31.84.54051 > 10.0.11.12.ddi-tcp-1: Flags [P.], seq 1:100, ack 1, win 115, length 99
E…..@.@.Z=
..T
….#”…O…SUP..s>…GET / HTTP/1.0
Host: http_backend
Connection: close
User-Agent: ApacheBench/2.3
Accept: */*
那么上面出现的现象就好解释了,是这样:
Nginx 和后端的长连接不够用时 Nginx 会新建连接来处理新的请求,而我们的配置已经配置死了 HTTP1.1,建立连接后,后端认为是「长连接」而不会主动关闭连接(一般有个空闲超时),关闭连接由 Nginx 来做了,所以 Nginx 会出现大量的 TIME_WAIT。
而默认情况下,Nginx 用 HTTP1.0 请求后端,后端处理完成后就主动关闭连接,所以 TIME_WAIT 在后端。
那么现在有新的问题了,如果开启了长连接,而长连接又大量不够用,此时 Nginx 存在的 TIME_WAIT 可能会大量占用端口,导致端口用尽,如果用尽,后果很严重。
————————————————————————————————————————
Nginx与upstream(后端)长连接的问题?
https://www.zhihu.com/question/30682780?sort=created
批注:nginx长连接消耗内存,但是少了,就会产生很多time-wait连接占用端口
这个数量确实有的聊,如何根据实际情况定量呢
多了浪费资源,少了,等于把time_wait转嫁给了ng,显然这风险要更大
推荐先做一下估算,根据QPS和响应时间计算出需要的长连接量。比如10000 QPS和100毫秒响应时间可以推算出的长连接数大概是1000. 将keepalive设置为这个长连接数的10%到50%。当然不考虑资源消耗的话,直接设置为keepalive=1000也OK
——————————————————————————————————————
[备忘]nginx开启长连接,减少TIME_WAIT数量
http://www.mytju.com/classcode/news_readnews.asp?newsid=935
批注:本文就在说nginx和tomcat在长连接得数量上要一致
keepalive 200;表示nginx与后端tomcat最多维持200个长连接。
注意,tomcat的connector有个参数maxKeepAliveRequests,是说最大保持长连接的数量,
默认是100。总之,nginx和tomcat要配合。
proxy_http_version 1.1; nginx与后端使用HTTP1.1协议,默认是1.0的
proxy_set_header Connection ""; 覆盖head头吧
-------------------------------------------------
不按以上设置的话,nginx默认和后端使用短连接,
数据传输完后,后端发起关闭,所以导致后端服务器有很多TIME_WAIT的连接,
保持5000(多少是跟一个linux设置有关),下不来。
打开长连接后,TIME_WAIT的值只有几百。
——————————————————————————————————————
也说说TIME_WAIT状态
https://www.cnblogs.com/yjf512/p/5327886.html
批注:主要思想-TIMEWAIT是主动断开方才会出现,一般情况下,nginx默认不开长连接,tomcat开且允许100个长连接,但无聊tomcat的情况是怎么样的,nginx发出的请求告诉tomcat你执行完了就关闭请求,所以tomcat端出现很多timewait
回到上面的问题,go写了一个HTTP服务,压测发现TIME_WAIT过多。
首先判断是不是压测程序放在服务的同一台机器...当然不会犯这么低级的错误...
那么这个感觉就有点奇怪了,HTTP服务并没有依赖外部mysql或者redis等服务,就是一个简单的Hello world,而TIME_WAIT的是主动断开方才会出现的,所以主动断开方是服务端?
答案是是的。在HTTP1.1协议中,有个 Connection 头,Connection有两个值,close和keep-alive,这个头就相当于客户端告诉服务端,服务端你执行完成请求之后,是关闭连接还是保持连接,保持连接就意味着在保持连接期间,只能由客户端主动断开连接。还有一个keep-alive的头,设置的值就代表了服务端保持连接保持多久。
HTTP默认的Connection值为close,那么就意味着关闭请求的一方几乎都会是由服务端这边发起的。那么这个服务端产生TIME_WAIT过多的情况就很正常了。
虽然HTTP默认Connection值为close,但是现在的浏览器发送请求的时候一般都会设置Connection为keep-alive了。所以,也有人说,现在没有必要通过调整参数来使TIME_WAIT降低了。
——————————————————————————————————————
提高tomcat的并发能力
4、采用Tomcat集群可以最大程度的发挥服务器的性能,可以在配置较高的服务器上部署多个Tomcat,也可以在多台服务器上分别部署Tomcat,Apache和Tomcat整合的方式还是JK方式。经过验证,系统对大用户量使用的响应方面,Apache+3Tomccat集群> Apache+2Tomcat集群 > Apache集成Tomcat > 单个Tomcat。并且采用Apache+多Tomcat集群的部署方式时,如果一个Tomcat出现宕机,系统可以继续使用,所以在硬件系统性能足够优越的情况下,需要尽量发挥软件的性能,可以采用增加Tomcat集群的方式。
5. 打开KeepAlive支持
KeepAlive on, KeepAliveTimeout 15 MaxKeepAliveRequests 1000
根据实际经验,通过Apache和Tomcat集群的方式提高系统性能的效果十分明显,这种方式可以最大化的利用硬件资源,通过多个Tomcat的处理来分担单Tomcat时的压力。
——————————————————————————————————————————
Linux下查看Nginx等的并发连接数和连接状态
http://www.linuxidc.com/Linux/2012-07/65411.htm
批注:查看timewait的两个命令
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ss -ant | awk 'NR>1 {++s[$1]} END {for(k in s) print k,s[k]}'
————————————————————————————————————————
记一次压测引起的nginx负载均衡性能调优
http://xiaorui.cc/2016/06/26/%E8%AE%B0%E4%B8%80%E6%AC%A1%E5%8E%8B%E6%B5%8B%E5%BC%95%E8%B5%B7%E7%9A%84nginx%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E6%80%A7%E8%83%BD%E8%B0%83%E4%BC%98/
批注:nginx设置keepalive-发现仍然很多短链接-nginx版本不行,换版本
nginx发送短链接-tomcat关闭timewait
nginx发送超出最大连接数的长连接-nginx关闭timewait
这一点很重要,也是最基本的要求,如果nginx worker连接数过少的化,你的请求连接就算没有被阻塞到backlog队列外,nginx worker也会因为过载保护不会处理新的请求。nginx的最大连接数是worker num *worker_connections, 默认worker_connections是1024, 直接干到10w就可以了。
——这是对客户端的,增加nginx对外并发能力
简单描述下nginx upstream keepalive是个怎么一回事?
默认情况下 Nginx 访问后端都是用的短连接(HTTP1.0),一个请求来了,Nginx 新开一个端口和后端建立连接,请求结束连接回收。
如过配置了http 1.1长连接,那么Nginx会以长连接保持后端的连接,如果并发请求超过了 keepalive 指定的最大连接数,Nginx 会启动新的连接 来转发请求,新连接在请求完毕后关闭,而且新建立的连接是长连接。
如果你的连接池的数控制在128,但因为你要应对更多的并发请求,所以临时又加了很多的连接,但这临时的连接是短连接和长连接要看你的nginx版本,我这1.8是长连接,那他如何被收回,两地保证,一点是他会主动去释放,另一点是keepalive timeout的时间。
————————————————————————————————————————
tcpdump抓取HTTP包
http://blog.csdn.net/kofandlizi/article/details/8106841
批注:tcp 3次握手 4次握手
TCP三次握手(创建 OPEN)
- 客户端发起一个和服务创建TCP链接的请求,这里是SYN(J) 客户端SYN_SEND
- 服务端接受到客户端的创建请求后,返回两个信息: SYN(K) + ACK(J+1) 服务端SYN_RECEIVED
- 客户端在接受到服务端的ACK信息校验成功后(J与J+1),返回一个信息:ACK(K+1) 客户端ESTABLISHED
- 服务端这时接受到客户端的ACK信息校验成功后(K与K+1),不再返回信息,后面进入数据通讯阶段
数据通讯
- 客户端/服务端 read/write数据包
TCP四次握手(关闭 finish)
- 客户端发起关闭请求,发送一个信息:FIN(M) 客户端FIN_WAIT1
- 服务端接受到信息后,首先返回ACK(M+1),表明自己已经收到消息。 服务端CLOSE_WAIT 客户端FIN_WAIT2
- 服务端在准备好关闭之前,最后发送给客户端一个 FIN(N)消息,询问客户端是否准备好关闭了 服务端LASK_ACK
- 客户端接受到服务端发送的消息后,返回一个确认信息: ACK(N+1) 客户端TIME_WAIT
- 最后,服务端和客户端在双方都得到确认时,各自关闭或者回收对应的TCP链接。
- keepAlive策略可以有效的避免进行三次握手和四次关闭的动作
1. http数据包抓取 (直接在终端输出package data)
tcpdump tcp port 80 -n -X -s 0 指定80端口进行输出
2. 抓取http包数据指定文件进行输出package
tcpdump tcp port 80 -n -s 0 -w /tmp/tcp.cap
————————————————————————————————————————————
nginx+tomcat的keepalive验证、bio/nio连接比较
http://blog.csdn.net/shi1122/article/details/50411885
批注:如何用wireshark查看连接是否是长短连接
抓包以后用wireshark看看目标请求的head,发现有connection:close,说明连接并非长连接。
——————————————————————————————————————————
学习了一圈后,将nginx与tomcat 的keepalive选项调整测试:
首先分析nginx 未设置keepalive情况,nginx发出短链接,后端tomcat收到connection:close信号关闭连接,无论tomcat如何设置,存在5000+个timewait,抓包后发现 显式存在 Connection:close标签,且前后三个请求端口不一样,证明是短链接
分析第2种情况,nginx keepalive 1000,tomcat 100,nginx发出1000个长连接请求,tomcat只接受100个,其它900个给你直接当短链接处理,故后端tomcat存在很多timewait,连接不够请求用,前端nginx只得再多开线程,且以默认长连接的形式发送,tomcat不做主返回nginx关闭,故前端也存在一些timewait,且当nginx keepalive设置为128时,前端存在大量timewait;
抓包后发现无Connection,且3次请求端口不一致,说明是存在短链接状态的
分析第3中情况,nginx keepalive 1000,tomcat 1000,两边基本对等,两边的timewait少了很多,tomcat当短链接处理的timewait少了,nginx则长连接够用,也更少的申请多开线程,故timewait也少了,抓包后发现无Connection,但3次请求端口一致,说明使用的同一个连接
好了,再做测试,1n1t 1n2t 20并发下qps仍然一样,晕了,那么排除长连接的可能
考虑第2个原因,nginx工作线程满了,顶不住,这个基本开到机器的峰值了,所以无法更进一步了
考虑第3个原因,压力还不够,看上去也够了,tomcat maxthread 5,实际压力有20并发,应当不存在一台tomcat直接解决问题导致qps一直一样的情况,是哪里错了?
发现tomcat有个参数:maxConnections,(BIO模式下默认最大连接数是它的最大线程数(缺省是200,同maxthreads),NIO模式下默认是10000)
有些地方说这个参数在bio模式下与maxthreads一致,所以就没管,一直是1000
http://blog.csdn.net/yy3097/article/details/50978410
比较容易弄混的是maxThreads和maxConnections这两个参数:
maxThreads是指Tomcat线程池做多能起的线程数,而 maxConnections 则是Tomcat一瞬间做多能够处理的并发连接数。比如maxThreads=1000,maxConnections=800,假设某一瞬间的并发时1000,那么最终Tomcat的线程数将会是800,即同时处理800个请求,剩余200进入队列“排队”,如果acceptCount=100,那么有100个请求会被拒掉。
注意:根据前面所说,只是并发那一瞬间Tomcat会起800个线程处理请求,但是稳定后,某一瞬间可能只有很少的线程处于RUNNABLE状态,大部分线程是TIMED_WAITING,如果你的应用处理时间够快的话。 所以真正决定Tomcat最大可能达到的线程数是maxConnections这个参数和并发数,当并发数超过这个参数则请求会排队,这时响应的快慢就看你的程序性能了。
acceptCount -当tomcat起动的线程数达到最大时,接受排队的请求个数。默认值为100,超出的会拒绝请求
当tomcat起动的且在用的线程数(或最大连接数)达到最大时,接受排队的请求个数。默认值为100,超出的会拒绝请求http://blog.csdn.net/kaka20099527/article/details/53285348 这个帖子里也有引用:
理解:
我们可以把tomcat比做一个电影院,流程是取号、买票、观影,acceptCount比作前厅(容纳取到号的人)、maxConnections比作大厅(容纳买到票的人)、maxThreads比作影厅(可以理解一个影厅只容纳一个人,因为一个线程同时只处理一个请求),以下场景是针对已达到maxConnections最大值来讨论的
1)取号:如果前厅人数已达到acceptCount,则拿号失败,会得到Connection refused connect的回复信息。反之则会进入前厅,等待买票。
2)买票:当大厅人数小于maxConnections时,前厅的人就可以进入大厅
3)观影:当影厅的人离开时,大厅的部分人能进入影厅,一般来讲大厅的容量要远大于影厅的数量。
tomcat会处理acceptCount+maxConnections的请求,说明只要取到号,有足够的耐心,就肯定能够看到电影
所以试着将这个参数缩小到与maxthreads一样是5,做一次单机测试:
(1)max_connection小了之后,事务数大幅度降低
(2)1n2t总算>>1n1t了
anyway,这是一次尝试,tps与
带宽 硬件 lvs nginx tomcat jvm 业务代码 cache db
都有关系,很复杂且非线性,没有经验丰富的运维和架构师比较难研究,仅做一次尝试吧