什么决定了同时连接的数量?

22
在Java servlet环境中,什么因素是限制同时用户数量的瓶颈。
  1. 服务器每个端口可以允许的HTTP连接数
  2. 服务器在多个端口上可以允许的HTTP连接数(我可以在多个HTTP端口上拥有多个WAS配置文件)
  3. 池中servlet的数量
  4. 为WAS配置用于服务连接的线程数
  5. 服务器可用的RAM(假设应用程序中没有内存泄漏,是否存在服务线程数与内存之间的相关性)
还有其他因素吗?
编辑: 为了排除业务逻辑因素,假设只有一个servlet在Log4j上打印一行。
  • 我的Tomcat服务器能否处理6000个同时的HTTP连接?为什么不行(文件句柄?每个请求的CPU时间?)?
  • 我可以将线程池大小设置为5000吗(空闲线程会消耗CPU/RAM)?
  • 我可以将Oracle连接池大小设置为500个连接吗(空闲连接会消耗CPU/RAM)?
每个连接生成的垃圾量是否会产生影响?例如,如果对于每个HTTP连接创建并留下20KB的对象,则在处理2500个请求时将使用100MB堆,并且这可能会触发300ms的GC暂停。
我们可以这样说吗:如果Tomcat每个HTTP请求处理需要0.2秒的CPU时间,则它每秒能够处理约500个HTTP连接。因此,6000个连接需要5秒钟。
6个回答

8

有趣的问题,如果我们忽略所有决定性能的属性,最终归结为在Servlet中执行了多少工作或者如果它具有最高的I/O、CPU和内存,则需要多少时间。现在让我们根据上述语句向下移动列表;

服务器每个端口可以允许的HTTP连接数

限制文件描述符,但这取决于Servlet完成请求所需的时间,或从请求第一个字节接收到完成发送整个响应所需的时间。因为如果只需要1毫秒,并且您正在使用Netty和持久连接,则可以达到非常高的>> 6000。

池中的Servlet数量

理论上可以超过6000个线程。但是有多少个线程正在处理您的请求?是否有一个线程池正在处理您的请求?所以您想增加线程,但是要增加多少呢?比如说2000个并发线程。您的CPU在上下文切换方面表现不佳吗?它是I/O绑定的吗?如果是,那么进行上下文切换是有意义的,但是那时您将会受到网络限制的影响,因为很多线程都在等待网络I/O,因此最终您会花费多少时间来完成一项工作。

数据库

如果是Oracle,那么连接管理会给您带来好处,您肯定需要严格监控这里。现在这只是另一个限制因素,并且可以被视为另一个阻塞I/O。根据I/O的定义,延迟/吞吐量很重要,一旦它变得大于最小的工作单元,就会成为瓶颈。

因此,最后,您需要为所有Servlet分解以下或更多属性。

  1. 这是一个CPU密集型任务吗?如果是,需要多少周期或者能否将其安全地转换为某个时间单位,例如只计算工作的1毫秒。
  2. 这是一个I/O密集型任务吗?如果是,同样找到单位。
  3. 以及其他的属性。
  4. 一个长长的列表,例如CPU、内存、GB/s等。

现在你知道需要完成多少工作,你所要做的就是通过已有的资源进行分配和调优,以便找到最佳方案,并找出您尚未考虑的其他属性并加以考虑。


1
你提供了我需要的东西,感谢提供相关链接。我希望能够合理地了解每种情况下的限制因素,无论是CPU周期、内存还是网络字节数等。这让我有了一个良好的开端。 - Teddy

8
我经历的最大瓶颈是处理请求所需的时间。 您能够更快地服务请求,就能处理更多的连接。
这是一个困难的问题,因为每个应用程序都不同。 为了解决这个问题,我创建了一个单元测试来生成许多线程,并在Eclipse中的VisualVM中监视内存使用情况。
您可以看到您的内存消耗如何随着使用的线程数量而变化。 并且您应该能够获得线程转储并查看线程使用的内存量。 您可以推断出平均值,以了解可能需要多少RAM才能支持N个用户。
瓶颈将是一个移动目标,因为您将优化一个区域,直到您可以扩展更大,然后另一个区域将成为您的瓶颈。
如果servlet的响应时间是瓶颈,您可以使用一些排队数学方法来确定根据平均响应时间可以最佳排队多少个请求。

http://www4.ncsu.edu/~hp/SSME_QueueingTheory.pdf

希望这可以帮到您。

更新以回答您的其他问题:

我的Tomcat服务器能处理6000个同时的HTTP连接吗?为什么不行(文件句柄?每个请求的CPU时间?)

可能是可能的,但很可能不行。如果您计划进行高流量操作,还应该在应用程序服务器前添加Web层。
假设有6000个用户都在使用您的应用程序。每个用户发送的请求只存在于服务器上一瞬间[希望如此],您的峰值线程数可能从未超过20。
我建议设置一些监控,了解您的应用程序在实际使用情况下的性能。查看http://Hawt.io,它使用Jolokia通过http获取JMX指标。
如果您真的关心分析,我建议使用类似Graphite之类的东西来聚合您的JMX指标。 https://github.com/graphite-project/graphite-web
我编写了一个Jolokia收集器,可以将指标发送到Carbon/Graphite,并且如果得到管理批准,可能会将其开源化。如果您有兴趣,请告诉我。

我可以将线程池大小设置为5000吗(空闲线程会消耗CPU / RAM)?
空闲线程不用太担心,但是将线程池设置得过高可能会导致您的应用服务器接收到太多请求。如果发生这种情况,您可能会使DB受到无法处理的连接洪水,或者您的内存分配可能无法处理如此多的请求。这可能会开始整体应用程序性能下降。
设置太低,您的应用程序服务器可能会再次排队请求,从而导致性能下降。
在峰值或高容量时有一些排队是正常的,但您不希望过载您的应用程序服务器。查看排队理论以了解更多信息。
此外,这就是在应用服务器前面拥有Web服务器可以帮助您的地方。如果Apache提供您的静态内容,则大多数情况下只有动态请求会到达应用程序服务器。
调整非常特定于您的个人应用程序。我建议保持默认设置,并优化您的代码,直到您可以收集足够的数据以知道应该转动哪个旋钮。
我可以将Oracle连接池大小设置为500个连接吗(空闲连接会消耗CPU / RAM)?
与应用程序线程池大小相同的情况。尽管您的数据库池大小应该比应用程序线程计数小得多。
除非您有非常高的流量,否则500对于大多数Web应用程序来说都太高了,在这种情况下,您可能需要像Oracle RAC这样的DB集群环境。
如果池设置过高并且开始使用大量连接,则您的DB硬件将无法跟上,并且您最终会在数据库服务器上遇到性能问题。
查询返回所需的时间可能会增加,反过来会导致应用程序响应时间增加。 “日志卡住”效应。
使用分析或指标确定正常使用下的平均活动DB连接数,并将其用作确定允许的最大值的基线。

每个连接生成的垃圾数量是否有影响?例如,如果为每个HTTP连接创建并留下Tomcat 20KB的对象..那么在处理2500个请求时将使用100MB堆,这可能会触发300ms的GC暂停。

数字会有所不同,但是是的。还记得完整的GC更值得关注。增量GC不会暂停您的应用程序。查看“并发标记和清除”和“Garbage First”。
如果Tomcat在处理单个HTTP请求时使用0.2秒的CPU时间,则它可以处理大约500个HTTP连接/秒。因此,6000个连接需要5秒钟。但实际情况并不是这么简单,因为每个请求进来的同时,也有一些正在被处理和完成。请查看排队理论以更好地理解此概念。http://www4.ncsu.edu/~hp/SSME_QueueingTheory.pdf

谢谢...非常好的观点。同时可以接收多少个HTTP连接? - Teddy
限制将与您的应用程序服务器可用线程数相关联。同时,请检查您的“ulimit”,因为每个http连接都会对此总数产生贡献。 - Jeremy
要知道您的应用程序可以处理多少个并发连接,首先需要通过分析了解线程的平均大小。然后,您可以使用数学方法来确定您的服务器可以支持多少个请求。但请记住,并发请求并不等于同时在线用户数。 - Jeremy

5
另一个常见的瓶颈是数据库连接池的大小。但我有一个额外的备注: 当您耗尽允许的HTTP连接数或允许服务请求的线程数时,您只会拒绝一些请求。但是当内存耗尽时(例如过多的会话和数据),您可能会使整个应用程序崩溃。
区别在于,在短时间内出现重负载时,当负载后来降下来时:
- 在第一种情况下,应用程序正常运行并可以正常处理请求。 - 在第二种情况下,应用程序已关闭并必须重新启动。
编辑:
我忘记提到真实的用例了。我曾经遇到的处理众多并发连接的最大问题是数据库请求的质量(假设您使用数据库)。由于没有最大数量,因此没有直接影响,但您可以轻松占用所有数据库服务器资源。常见的不良数据库请求示例:
- 没有索引的具有大量行的表 - 未使用任何索引的请求(在大型表上) - n+1综合症:使用ORM将一对多关系映射到集合时,如果您总是需要从集合中获取数据,则不要急切地获取 - 全部加载数据库综合症:使用ORM将所有关系映射为急切时,任何单个请求都会导致加载大量相关数据。
这些问题更糟糕的是,它们在数据库年轻时可能不会造成任何损害,因为没有那么多行,但是随着时间和行数增加,性能下降,使得应用程序无法使用,即使只有少数用户。

现代框架通过重复使用已经被占用的连接来避免数据库连接池大小的限制,因此这应该不是太大的问题。 - Tomas Smagurauskas
2
@TomasSmagurauskas,我不明白你的观点:重用连接是池的作用。 - Serge Ballesta
@Teddy:帖子已更新,加入了另一个常见的并发问题。 - Serge Ballesta
@SergeBallesta,我同意您关于性能广泛方法的看法。我的问题有点更加理论化。是否有一个经验法则,例如“每个线程占用最少300KB内存..因此仅拥有800个空闲线程池将占用240MB”?我只是试图了解我的应用程序的每个部分如何消耗资源。 - Teddy
@Teddy - 线程的大小取决于该线程正在执行的任务。您创建了多少变量,它们的类型是什么,是否访问静态资源等等都会影响线程大小。 除了内存使用情况外,您还需要监视处理请求所需的实际时间并进行优化。 - Jeremy

4

每个端口服务器可以允许的HTTP连接数

除了内核资源(例如FDs、套接字缓冲区等)之外,无限制。

服务器可以允许的跨多个端口的HTTP连接数(我可以在几个HTTP端口上拥有多个WAS配置文件)

由于每个端口的连接数是无限的,因此这不相关。

池中Servlet的数量

除了增加传入请求的速率外,这不相关。

为WAS配置使用来服务连接的线程数

以间接方式相关,请参见下文。

服务器可用的RAM(假设应用程序没有0内存泄漏),是否存在线程数与内存之间的关联?

如果它将线程数限制在上述配置的线程数以下,则相关。

根本限制是请求服务时间。时间越短,越好。它越长,线程就会被绑定在该请求中,等待队列就会变长......排队理论规定“甜点”是不超过70%的服务器利用率。超过这个范围,等待时间随着利用率的增加而迅速增加。

因此,任何增加请求服务时间的因素都是重要的:例如线程池大小、连接池大小、并发瓶颈等。


谢谢。我还是有点困惑。如果我有一个只打印一行到Log4j的servlet,它能处理Tomcat上500 MB堆大小的6000个同时请求吗?会有一些连接被丢弃吗?为什么会被丢弃?我能将线程池大小配置为1000或Oracle连接池大小配置为500个连接吗?一个线程的成本是多少(仅指线程本身,不包括业务逻辑)?保持单个Oracle连接开放的成本是多少(每个连接2MB的RAM)? - Teddy

3
您还需要考虑到使用情境本身会限制并发的数量。想象一下一个顺序相关的协作环境。这迫使您同步操作,即使您本来可以同时处理它们。
在Java中,这可能只是共享单个资源,该资源使用阻塞访问(例如共享的随机数生成器(不是每个线程),共享向量,像ConcurrentHashMap这样的并发结构)。
同步越多,您将无法充分利用服务器硬件。
因此,除了内存耗尽、CPU饱和或垃圾回收限制外,这种同步可能是一个问题,不仅需要在您的代码中解决,甚至可能需要软化高级工作流程的某些要求。

谢谢。同意你的观点,业务逻辑和算法是最重要的。只是想知道如果我有一个仅仅打印一行到Log4j的servlet,它能够在500 MB堆大小的Tomcat上处理6000个并发请求吗?是否会丢失一些连接?为什么会丢失连接? - Teddy

-1

看到第6点,你可以使用这些工具来查看硬件是否成为瓶颈:假设你使用的是Linux,你可以使用VmStat查看RAM使用情况的一些统计信息,topatop(取决于你的发行版)来查看占用CPU和RAM的进程,nloadiftop来查看正在消耗网络带宽的内容,以及iotop来查看正在读写你的磁盘的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接