奇怪的Tomcat中断,可能与maxConnections有关

时间:2014-09-10 13:05:30

标签: linux tomcat tomcat7

在我的公司,我们今天遇到了严重问题:我们的生产服务器出现故障。大多数通过浏览器访问我们软件的人无法获得连接,但是已经使用该软件的人能够继续使用它。甚至我们的热备用服务器也无法与生产服务器通信,它使用HTTP进行通信,甚至无法访问更广泛的互联网。服务器可以通过ping和ssh访问的整个时间,实际上是非常负载 - 它通常以5%的CPU负载运行,而且此时甚至更低。我们几乎没有磁盘i / o。

问题开始几天后,我们有了一个新的变化:端口443(HTTPS)正在响应,但端口80停止响应。服务器负载非常低。重新启动tomcat后,端口80立即开始响应。

我们使用tomcat7,maxThreads =" 200",并使用maxConnections = 10000。我们从主内存中提供所有数据,因此每个HTTP请求都很快完成,但是我们有大量用户进行非常简单的交互(这是高中科目选择)。但是我们似乎不太可能同时拥有10,000个用户同时在我们的页面上打开浏览器。

我的问题有几个部分:

  • 可能是" maxConnections"参数是造成我们困境的原因吗?
  • 有没有理由不设置" maxConnections"一个非常高的价值,例如100000? (即这样做的成本是多少?)
  • tomcat一旦到达" maxConnections"就会在任何地方输出警告信息。信息? (我们没有注意到任何事情)。
  • 我们可能会遇到操作系统限制吗?我们正在使用CentOS 6.4(Linux)和" ulimit -f"说"无限制"。 (防火墙是否了解Tcp / Ip连接的概念?其他地方是否存在限制?)
  • 当tomcat遇到" maxConnections"限制?它是否尝试关闭一些不活动的连接?如果没有,为什么不呢?我不喜欢这样的想法:我们的服务器可以被拥有浏览器的人收取赎金,发送保持活动以保持连接畅通。

但主要的问题是,"我们如何修复我们的服务器?"

Stefan和Sharpy要求的更多信息:

  • 我们的客户直接与此服务器通信
  • 在某些情况下,TCP连接被立即拒绝,在其他情况下超时
  • 即使将我的浏览器连接到网络中的服务器,或者热备用服务器(也在同一网络中)无法执行通常通过HTTP发生的数据库复制消息,问题就很明显了
  • IPTables - 是的,IPTables6 - 我不这么认为。无论如何,当我在注意到问题后进行测试时,我的浏览器和服务器之间什么都没有。

更多信息: 当我们意识到我们使用BIO的默认Tomcat7设置(每个连接有一个线程,并且我们有maxThreads = 200)时,看起来我们已经解决了问题。实际上' netstat -an'显示了大约297个连接,其中200个队列为100个。因此我们将其更改为NIO并重新启动了tomcat。不幸的是,第二天发生了同样的问题。我们可能错误配置了server.xml。

这里提供了catalina.out的server.xml和摘录: https://www.dropbox.com/sh/sxgd0fbzyvuldy7/AACZWoBKXNKfXjsSmkgkVgW_a?dl=0

更多信息: 我做了负载测试。我能够从我的开发笔记本电脑创建500个连接,并且每个都进行3次HTTP GET,没有任何问题。除非我的负载测试无效(Java类也在上面的链接中)。

5 个答案:

答案 0 :(得分:3)

如果没有亲自动手的调试,很难确定,但我要检查的第一件事就是文件描述符限制(即ulimit -n)。 TCP连接使用文件描述符,并且根据正在使用的实现,使用SelectableChannel进行轮询的nio连接可能会为每个打开的套接字吃掉几个文件描述符。

检查这是否是原因:

  • 使用ps
  • 查找Tomcat PID
  • 检查ulimit流程是否运行:cat /proc/<PID>/limits | fgrep 'open files'
  • 检查实际使用的描述符数量:ls /proc/<PID>/fd | wc -l

如果使用的描述符数量明显低于限制,则还有其他原因导致问题。但如果它等于或非常接近极限,那么这就是造成问题的限制。在这种情况下,您应该为运行Tomcat帐户的用户增加/etc/security/limits.conf的限制,并从新打开的shell重新启动进程,如果实际使用了新限制,请使用/proc/<PID>/limits进行检查,并查看如果Tomcat的行为得到改善。

答案 1 :(得分:2)

虽然我没有直接的答案来解决你的问题,但我想提供我的方法来找出问题所在。

直观地有3个假设:

  1. 如果您的客户端保持连接并且永不释放,即使没有通信,您的服务器也很可能达到最大连接限制。
  2. 也可以通过各种方式访问​​无响应状态,例如服务器端代码中的错误。
  3. 不应忽视硬件条件。
  4. 要找出此问题的原因,您最好尝试在测试环境中重播该方案。执行更全面的测试并记录更详细的日志,包括但不限于:

    • 单元测试,尤其是使用事务,线程和同步的逻辑块。
    • 面向压力的测试。尝试模拟您可以提出的所有用户行为及其组合,并以大批量模式进行测试。 (ref
    • 更多指定的记录。跟踪客户端行为并分析在服务器停止响应之前发生的事情。
    • 更换服务器计算机并查看它是否仍会发生。

答案 2 :(得分:1)

你绝对确定你没有达到maxThreads限制吗?你试过改变吗?

目前浏览器将同时连接限制为每个主机名/ ip最多4个,因此如果您有50个并发浏览器,则可以轻松达到该限制。虽然希望您的webapp能够快速响应以应对此问题。如今,漫长的民意调查越来越受欢迎(直到网页插播更为普遍),所以你可能有200个长期民意调查。

另一个原因可能是你使用HTTP [S]进行app-to-app通信(也就是说,不涉及浏览器)。有时,应用程序编写者很邋and并创建新的连接以并行执行多个任务,从而导致TCP和HTTP开销。仔细检查您是否没有获得任何请求。日志文件通常可以帮助您,或者您可以使用wireshark来计算HTTP请求或HTTP [S]连接的数量。如果可能,请修改您的API以在一个HTTP请求中处理多个API调用。

与最后一个相关,如果您有多个HTTP / 1.1请求通过一个连接,并且中间代理可能会将它们拆分为多个连接以实现负载平衡。听起来很疯狂我知道,但我已经看到它发生了。

最后,一些抓取机器人会忽略robots.txt中设置的抓取延迟。同样,日志文件和/或wireshark可以帮助您确定这一点。

总体而言,通过更多更改运行更多实验。在使用maxConnections跳到结论之前,请使用maxThreads,https等。

答案 3 :(得分:1)

答案简短:

  • 使用NIO连接器代替默认BIO连接器
  • 将“maxConnections”设置为合适的值,例如万
  • 鼓励用户使用HTTPS,以便中间代理服务器无法将100个页面请求转换为100个TCP连接。
  • 检查由于死锁问题导致的线程悬挂,例如:堆栈转储(kill -3)
  • (如果适用,如果您还没有这样做,请编写您的客户端应用程序以使用一个连接来处理多个页面请求。)

答案很长:

我们使用的是BIO连接器而不是NIO连接器。两者之间的区别在于BIO是“每个连接一个线程”而NIO是“一个线程可以为多个连接提供服务”。因此,如果我们不增加“maxThreads”,那么增加“maxConnections”就无关紧要了,因为我们没有理解BIO / NIO的差异。

要将其更改为NIO,请将其放在server.xml中的元素中:                 协议= “org.apache.coyote.http11.Http11NioProtocol”

据我所知,使用BIO没有任何好处所以我不知道为什么它是默认的。我们只使用它,因为它是默认设置,我们假设默认设置是合理的,我们不想成为tomcat调优的专家,达到我们现在的程度。

但是:即使在进行此更改之后,我们也发生了类似的事情:在同一天,即使HTTP正在运行,HTTPS也没有响应,然后稍后相反的情况发生了。这有点令人沮丧。我们检查了'catalina.out',实际上正在使用NIO连接器,而且确实如此。所以我们开始了很长一段时间来分析'netstat'和wireshark。我们注意到连接数量出现了一些高峰期 - 在一个案例中,当基线大约为70时,多达900个连接。当我们在主要生产服务器和我们为每个客户安装的“设备”之间同步数据库时,出现了这些高峰网站(学校)。我们进行同步的次数越多,我们造成的中断就越多,这导致我们在下降的螺旋中进行更多的同步。

似乎正在发生的事情是,新南威尔士州教育部代理服务器将我们的数据库同步流量拆分为多个连接,以便1000个页面请求变为1000个连接,而且直到TCP 4分钟超时才能正常关闭它们。代理服务器只能这样做,因为我们使用的是HTTP。他们这样做的原因可能是负载平衡 - 他们认为通过在4个服务器上拆分页面请求,他们可以获得更好的负载平衡。当我们切换到HTTPS时,他们无法执行此操作并被迫仅使用一个连接。因此消除了这个特殊问题 - 我们不再看到连接数量突然增加。

人们建议增加“maxThreads”。实际上这会改进一些东西,但这不是“正确的”解决方案 - 我们的默认值为200,但在任何给定的时间,几乎没有任何东西做任何事情,实际上几乎没有任何一个甚至分配给页面请求

答案 4 :(得分:0)

我认为您需要使用Apache JMeter调试应用程序的连接数,并使用Jconsole或Zabbix为tomcat服务器查找堆空间或线程转储。

Apache tomcat的Nio连接器可以有10000的最大连接但我不认为提供那么多连接到一个tomcat实例的好主意更好的方法是运行tomcat的多个实例。

在我看来,生产服务器的最佳方式:在前面运行Apache http服务器,并使用AJP连接器将tomcat实例指向该http服务器。

希望这有帮助。