我正在使用 apache bench 对在 tomcat 上运行的 java 应用程序进行一些基准测试。
假设我运行如下测试:
ab -c 10 -n 10000 http://localhost:8080/hello/world
它会运行得很好。如果我按照以下操作:
ab -c 50 -n 50000 http://localhost:8080/hello/world
再次,它将运行良好,但如果我再试一次,大约在完成 3500 个请求后,它就会开始变慢。
我需要帮助来尝试调试这个问题的根本原因。
我运行了 top,并且有几 GB 的内存未使用,因此内存似乎不是问题。
tomcat6进程确实会到70-80甚至107%。
重新启动 tomcat 似乎可以解决问题,但有时需要重新启动服务器。
这是在默认的 tomcat 安装中分配了 200 个线程。
Tomcat 日志是空的。
更新
因此我将 tcp_tw_recycle/reuse 都改为 1,现在运行 netstat 显示的计数非常低。
在更改 tcp_tw_recycle/reuse 之前,我注意到速度变慢了,并运行了 netstat,发现有 32400 个 tcp TIME_WAIT 连接。
因此,现在更新一下基准测试,使用 -k 开关后,我看到吞吐量大大增加。但是,在某些时候,速度又开始变慢,但重新启动 tomcat 现在可以恢复正常。以前,即使我重新启动 tomcat,运行 ab 的响应时间也会非常非常慢。 现在,在更改 tcp_tw_recycle/reuse 之后,重新启动 tomcat 即可恢复正常。运行 top 显示 tomcat 的 CPU 占用率仅为 20% 左右,因此现在看来问题出在 tomcat 上,但我该如何找出问题所在呢?
答案1
这里可能发生了一些事情。上面的命令转换为 50 个并发连接,每个连接发出 1000 个请求。这里要注意的一点是,如果我没记错的话,apachebench 默认不启用 keep alive。可能值得添加这个(将 -k 传递给上面的命令)。无论如何,这将更像是一个真实世界的测试,因为大多数用户代理都默认使用 keep-alive,Tomcat 也是如此。如果我下面的理论是正确的,这应该有助于解决问题。
1) 我怀疑您向线程池发送了太多请求,因为每个请求都在崩溃。这对这些线程以及系统上的 TCP/IP 堆栈造成了相当大的打击。这让我想到...
2) 您可能(好吧,您很可能)用完了临时端口或遇到了 TIME_WAIT 套接字。如果每个请求确实是一个新的、唯一的请求,那么您很可能会遇到 TIME_WAIT 情况,并且有数千个套接字处于该状态(在加载期间查看 netstat -an |grep -ic TIME_WAIT 以了解它们的数量)。除非您在系统上启用了 time_wait_reuse,否则这些套接字将无法重新使用。您使用 localhost 只会使情况变得更糟。
有关设置 time_wait 重用的更多信息,请参阅这里。还请注意,此线程正确指出设置 fin_wait 超时是不正确在 time_wait 上下文中,所以要避免这种情况。在 TIME_WAIT 上下文中触发 fin_wait 是错误的,不会对你有帮助。
因此,请查看并特别调整 tcp_tw_recycle/reuse。这些将帮助您完成测试,keep-alive 也是如此。