zoukankan      html  css  js  c++  java
  • 一次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连接占用端口

    这个keepalive 16就是每个worker(进程?)和upstream保持的长连接数。
     
     

    这个数量确实有的聊,如何根据实际情况定量呢

    多了浪费资源,少了,等于把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的并发能力

    https://www.cnblogs.com/linjiqin/p/4430269.html
     
    批注:主要思想-对多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)

    1. 客户端发起一个和服务创建TCP链接的请求,这里是SYN(J)  客户端SYN_SEND
    2. 服务端接受到客户端的创建请求后,返回两个信息: SYN(K) + ACK(J+1)     服务端SYN_RECEIVED
    3. 客户端在接受到服务端的ACK信息校验成功后(J与J+1),返回一个信息:ACK(K+1)    客户端ESTABLISHED
    4. 服务端这时接受到客户端的ACK信息校验成功后(K与K+1),不再返回信息,后面进入数据通讯阶段

    数据通讯

    1. 客户端/服务端 read/write数据包

    TCP四次握手(关闭 finish)

    1. 客户端发起关闭请求,发送一个信息:FIN(M)   客户端FIN_WAIT1
    2. 服务端接受到信息后,首先返回ACK(M+1),表明自己已经收到消息。   服务端CLOSE_WAIT   客户端FIN_WAIT2
    3. 服务端在准备好关闭之前,最后发送给客户端一个 FIN(N)消息,询问客户端是否准备好关闭了 服务端LASK_ACK
    4. 客户端接受到服务端发送的消息后,返回一个确认信息: ACK(N+1)         客户端TIME_WAIT
    5. 最后,服务端和客户端在双方都得到确认时,各自关闭或者回收对应的TCP链接。  
      1. 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的的包,可以看到有keepalive: 

    ——————————————————————————————————————————

     

     

     

    学习了一圈后,将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这个参数和并发数,当并发数超过这个参数则请求会排队,这时响应的快慢就看你的程序性能了。

     
    还是不懂,不管了,网络上也没有说的比较清楚的,可能要深入源码,个人感觉是,这个tomcat配置可以同时接受1000个请求,由于请求简单很快就搞定了,于是5个线程也够用,所以我认为:
    acceptCount -当tomcat起动的线程数达到最大时,接受排队的请求个数。默认值为100,超出的会拒绝请求
    当tomcat起动的且在用的线程数(或最大连接数)达到最大时,接受排队的请求个数。默认值为100,超出的会拒绝请求
    http://blog.csdn.net/kaka20099527/article/details/53285348 这个帖子里也有引用:
    Note that once the limit has been reached, the operating system may still accept connections based on the acceptCount setting.
    其中maxConnections描述红色部分说明当连接数达到最大值后,系统会继续接收连接但不会超过acceptCount的值。

    理解:

    我们可以把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

    都有关系,很复杂且非线性,没有经验丰富的运维和架构师比较难研究,仅做一次尝试吧

  • 相关阅读:
    WebApi 安全认证
    Autofac 学习
    autofac实现批量注入
    Autofac -入门练习
    Struts2 Namespace_命名空间
    Deployment failure on Tomcat 6.x. Could not copy all resources
    chm 已取消到该网页的导航 或者 无法显示网页 的问题
    GPT 分区详解
    mount 中文手册
    rpm 中文手册
  • 原文地址:https://www.cnblogs.com/silyvin/p/9106692.html
Copyright © 2011-2022 走看看