Tomcat性能调优
1、参数设置
Springboot集成的tomcat默认采从的是NIO(非阻塞队列)方式创建http链接,NIO相比普通BIO(阻塞队列)来说,参数设置上有很大不同:
NIO方式下并发访问取决于maxConnections参数,BIO模式下取决于maxThreads(一个链接对应一个线程)
关键参数说明
NIO下默认设置值:
maxConnections=10000
maxKeepAliveRequests=100 //支持的长链接个数,1表示禁用长链接,-1表示不限制个数
keepAliveTimeout=20000ms //长链接持续时长,表示这个链接在执行完一个请求后,可以继续存活20s, 如果这个参数不设置,就取connecttimeout做为长链接支持时长,
这个值引发的安全问题,比如这个值设置为20s, 恶意用户可以用多台电脑向该服务器发请求,每18s(小于20s就可以)发一次,导致这链接一直都被占用,从而无法释放,耗尽链接资源。
目前测试浏览器与esm微服务 访问是存在这样问题的。
(在开发环境很好模拟,把maxConnections设置为2,只要两个用户在不同电脑上用浏览器访问,间隔刷新,会发现第三个用户访问时访问不了)
Tips:将附件中 GetSysInfoServlet.java放入到springboot项目的任意目录下,然后访问http://xxx/上下文/monitor/thread 动态监控所有web容器中的线程。
例子: http://api.uds.zte.com.cn/zte-sec-terminal-base/monitor/thread
对于长链接的监控,用netstat |findstr ip命令 (或采用wireshark可以抓包分析更多明细),会发现TCP链接的端口号未变化,即表示采用的是长链接,目前我们微服务因为通过ng/haproxy代理,实际上长链接是建立在ng/haproxy与客户端之间,这时候keepAliveTimeout的时长其实就取决于haproxy的链接超时实际,就是一分钟,而不是我们tomcat里面的设置。
2、长链接访问
通过wireshark抓包我们发现浏览器都能复用tcp链接,说明长链接是生效的,但在httpclient调用过程中,抓包发现tcp链接其实是没有复用的,可以采用如下方式做到链接的复用,减少创建链接的损耗:
public class HttpClientUtil
{
static PoolingHttpClientConnectionManager cm = null;
static
{
cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(500);
cm.setDefaultMaxPerRoute(500);
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(true)
.build();
cm.setDefaultSocketConfig(socketConfig);
}
public static CloseableHttpClient getClient()
{
CloseableHttpClient httpClient=HttpClients.custom().setConnectionManager(cm).build();
return httpClient;
}
}
在开发环境中做压力测试,这个性能提升非常明显,但是在生成环境,建立的链路比较多,只能确保在用户请求到ng/haproxy这个链路是长链接,而ng/haproxy到微服务这一层我们就没法控制了,而对于公用资源haproxy,如果使用长链接过多,有链接耗尽的风险,但微服务之间的调用,如果用长链接方式这个风险应该不存在。