什么决定了同时连接的数量
Posted
技术标签:
【中文标题】什么决定了同时连接的数量【英文标题】:What determines number of simultaneous connections 【发布时间】:2014-12-21 23:47:50 【问题描述】:在 Java servlet 环境中,哪些因素是同时用户数量的瓶颈。
-
服务器每个端口允许的 HTTP 连接数
服务器允许跨多个端口的 HTTP 连接数(我可以在多个 HTTP 端口上拥有多个 WAS 配置文件)
池中的 servlet 数量
为 WAS 配置用于服务连接的线程数
服务器可用的 RAM(假设应用程序中的内存泄漏为 0,服务线程数之间是否存在任何关联)
还有其他因素吗?
编辑: 为了不考虑业务逻辑,假设只有一个 servlet 在 Log4j 上打印一行。
我的 Tomcat 服务器可以同时处理 6000 个 HTTP 连接吗?为什么 不是(文件句柄?每个请求的 CPU 时间?)? 我可以将线程池大小设为 5000(空闲线程会消耗 CPU/RAM)吗? 我能否将 oracle 连接池大小设置为 500 个连接(空闲 连接会消耗 CPU/RAM)?每个连接产生的垃圾量有影响吗?例如,如果 Tomcat 为每个 HTTP 连接创建并留下 20KB 的对象。那么到处理 2500 个请求时,将使用 100MB 堆,这可能会触发 300 毫秒的 GC 暂停。
我们可以这样说吗:如果 Tomcat 使用 0.2 秒的 CPU 时间来处理单个 HTTP 请求,那么它将能够在一秒钟内处理大约 500 个 http 连接。因此,6000 个连接需要 5 秒。
【问题讨论】:
【参考方案1】:有趣的问题,如果我们不考虑所有决定性能的属性,最终归结为您在 servlet 中做了多少工作,或者如果它具有最高的 I/O、CPU 和内存,则需要多少时间。现在让我们带着上面的陈述向下移动列表;-
服务器每个端口允许的 HTTP 连接数
文件描述符有limit,但这又会被 servlet 完成请求所花费的时间或从请求第一个字节接收到完成发送整个响应所花费的时间触发。因为如果只需要 1ms 并且你使用的是 Netty 和持久连接,你可以达到非常高的 >> 6000。
池中的 servlet 数量
理论上>> 6000。但是有多少线程正在处理您的请求?是否有一个线程池正在燃烧您的请求?所以你想增加线程,但是有多少可以说 2000 个并发线程。您的 CPU 在上下文切换时表现不佳吗?是否受 I/O 限制?如果是的话,上下文切换是有意义的,但是你会遇到这些网络限制,因为很多线程在网络 I/O 上等待,所以最终你花了多少时间在一项工作上。
数据库
如果是oracle,祝福你有连接管理,这里肯定需要严格的监控。现在这只是另一个限制因素,可以被视为另一个阻塞 I/O。根据 I/O 的定义,延迟/吞吐量很重要,一旦它变得比最小的工作更大,它就会成为瓶颈。
所以,最后,您需要分解所有 servlet 的以下或更多属性
-
是否受 CPU 限制?如果是,它需要多少周期或者可以安全地转换为某个时间单位。例如仅计算工作需要 1 毫秒。
是否受 I/O 限制,如果是,同样查找单元。
及其他
您拥有的一长串清单,例如CPU、内存、GB/s
现在您知道需要完成多少工作,您所做的就是除以现有资源并不断调整,这样您就可以找到最佳的并找出您没有考虑的其他属性并考虑它们。
【讨论】:
你得到了我正在寻找的东西......感谢相关链接。我希望对每种情况下的限制因素有一个合理的理解。无论是 CPU 周期还是内存或网络字节等。这让我开始了。【参考方案2】:我遇到的最大瓶颈是处理请求所需的时间。 处理请求的速度越快,可以处理的连接就越多。
由于每个应用程序都不同,这是一个很难回答的问题。 为了解决我支持的应用程序的问题,我创建了一个生成许多线程的单元测试,并在 eclipse 中观察 VisualVM 中的内存使用情况。
您可以看到您的内存消耗如何随着正在使用的线程数而变化。 您应该能够获得线程转储并查看线程正在使用多少内存。 您可以推断出一个平均值,以了解 N 个用户可能需要多少 RAM。
瓶颈将是一个移动的目标,因为您将优化一个区域直到您可以扩大规模,然后另一个区域将成为您的瓶颈。
如果 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)吗?
空闲线程不必担心,尽管将线程池设置得太高可能会让应用服务器接收到过多的请求。如果发生这种情况,您最终可能会用无法处理的连接淹没您的数据库,或者您的内存分配可能不足以处理如此多的请求。这可能会导致整体应用程序性能下降。 设置得太低,您的应用服务器可能会再次开始排队请求,从而导致性能下降。 在高峰期或高容量时间通常会有一些排队,但您不希望应用程序服务器超载。查看排队理论以了解更多信息。 此外,这也是在应用程序服务器前面有一个 Web 服务器可以为您提供帮助的地方。如果您让 Apache 为您的静态内容提供服务,那么在大多数情况下,只有动态请求会到达应用程序服务器。 调优对您的个人应用程序非常具体。我建议保留默认值并优化您的代码,直到您可以收集足够的数据来知道应该转动哪个旋钮。
我可以将 oracle 连接池大小设置为 500 个连接(空闲连接是否会消耗 CPU/RAM)?
与应用程序线程池大小相同的情况。尽管您的数据库池大小应该比应用程序线程数小得多。 500 对于大多数 Web 应用程序来说太高了,除非您的容量非常大,在这种情况下,您可能需要像 Oracle RAC 这样的数据库集群环境。 如果池设置得太高并且您开始使用大量连接,则您的数据库硬件将无法跟上,最终您将在数据库服务器上遇到性能问题。 查询返回所需的时间可能会增加,进而导致您的应用程序响应时间增加。 “原木堵塞”效应。 使用分析或指标来确定正常使用下活动数据库连接的平均数量,并将其用作确定允许的最大值的基线。
每个连接产生的垃圾量有影响吗?例如,如果 Tomcat 为每个 HTTP 连接创建并留下 20KB 的对象。那么到处理 2500 个请求时,将使用 100MB 堆,这可能会触发 300 毫秒的 GC 暂停。
数字会有所不同,但可以。还记得Full GC比较受关注。增量 GC 不会暂停您的应用程序。查看“并发标记和清除”和“垃圾优先”。
我们可以这样说吗:如果 Tomcat 使用 0.2 秒的 CPU 时间来处理单个 HTTP 请求,那么它将能够在一秒钟内处理大约 500 个 http 连接。因此,6000 个连接需要 5 秒。
这并不是那么容易,因为每个请求都进来了,还有一些正在处理和完成。查看排队理论以更好地理解这一点。 http://www4.ncsu.edu/~hp/SSME_QueueingTheory.pdf
【讨论】:
谢谢... 好点。可以接收的同时 http 连接有什么限制吗? 限制将与您的应用程序服务器可用的线程数相关联。还要检查你的“ulimit”,因为每个 http 连接都对这个总数有贡献。 要了解您的应用程序可以处理多少同时连接,您需要首先通过分析了解线程的平均大小。然后您可以使用数学来确定您的盒子可以支持多少请求。但请记住,同时请求不等于同时用户。【参考方案3】:服务器每个端口允许的 HTTP 连接数
除内核资源外不受限制,例如FD、socket buffer soace等
服务器允许跨多个端口的 HTTP 连接数(我可以在多个 HTTP 端口上拥有多个 WAS 配置文件)
由于每个端口的连接数是无限的,这无关紧要。
池中的 servlet 数量
无关紧要,除非它增加了传入请求的速率。
为 WAS 配置的用于服务连接的线程数
以间接方式相关,见下文。
服务器可用的 RAM(假设应用程序中的内存泄漏为 0,服务线程数之间是否存在任何关联)
如果它限制线程数低于上述配置的线程数,则相关。
基本限制是请求服务时间。越短越好。时间越长,线程在该请求中占用的时间越长,等待队列的时间就越长……排队理论表明,“最佳位置”是服务器利用率不超过 70%。除此之外,等待时间随着利用率的提高而迅速增长。
所以任何影响请求服务时间的因素都很重要:例如,线程池大小、连接池大小、并发瓶颈……
【讨论】:
谢谢。我还是有点困惑。如果我有一个只向 Log4j 打印一行的 servlet,它能否处理 500 MB 堆大小的 Tomcat 上的 6000 个并发请求?一些连接会被丢弃吗?为什么他们会被丢弃?我可以将线程池大小配置为 1000 或将 Oracle 连接池大小配置为 500 个连接吗?一个线程的成本是多少(只是线程本身,而不是业务逻辑)?保持单个 oracle 连接打开的成本是多少(每个连接需要 2MB RAM?)?【参考方案4】:您还应该考虑到用例本身限制了并发量。想象一个协作环境,其中行动的顺序很重要。这会迫使您同步操作 - 即使您能够一次处理所有操作。
在 Java 领域,这可能是一件简单的事情,比如共享使用阻塞访问的单个资源。 (例如,共享随机数生成器(不是每个线程)、共享向量、并发结构(如 ConcurrentHashMap 等)。
同步越多,您就无法充分利用服务器硬件。
因此,除了内存不足、CPU 饱和或达到垃圾收集限制之外,这种同步可能是一个问题,不仅需要在您的代码中解决,甚至可能需要您软化一些高级别的要求工作流程。
【讨论】:
谢谢。同意你的观点,业务逻辑和算法最重要。只是想知道我是否有一个只向 Log4j 打印一行的 servlet 是否可以处理 500 MB 堆大小的 Tomcat 上的 6000 个同时请求?某些连接会被丢弃吗?为什么会被丢弃?【参考方案5】:还有另一个常见的瓶颈:数据库连接池的大小。但我有一个补充说明:当你用尽允许的 HTTP 连接数,允许服务请求的线程数时,你只会拒绝一些请求。但是当您耗尽内存时(例如过多的会话和过多的数据),您可能会导致整个应用程序崩溃。
不同的是,在短时间重载的情况下,稍后负载下降时:
在第一种情况下,应用程序已启动并可以正常处理请求 在第二种情况下,应用程序已关闭,必须重新启动编辑:
我忘了记住真实的用例。我发现为大量并发连接提供服务的最大问题是数据库请求的质量(假设您使用数据库)。由于没有最大数量,因此没有直接影响,但您可以轻松占用所有数据库服务器资源。不良数据库请求的常见示例:
在具有大量行的表上没有索引 一个不使用任何索引的请求(在一张大桌子上) n+1 综合症:当您将一对多关系映射到集合时使用 ORM,当您总是需要来自集合的数据时,不要急于求成 加载完整数据库综合症:使用 ORM 时,当您将所有关系映射为渴望时,任何单个请求都会以加载大量相关数据而告终。这些问题更糟糕的是,当数据库年轻时,它们不会对测试造成伤害,因为没有那么多行,但随着时间的推移和行数的增加,性能下降,导致应用程序在少数用户中无法使用。
【讨论】:
现代框架通过重用已经建立的连接来绕过数据库连接池的大小,所以我想这应该不是太大的问题。 @TomasSmagurauskas 我无法理解您的观点:重用连接是池的用途。 @Teddy : 更新了另一个常见并发问题。 @SergeBallesta 我同意你关于性能的广泛方法。我的问题更具理论性。有没有像“每个线程至少拥有 300KB 内存......所以只有 800 个空闲线程池会吃掉 240MB”这样的经验法则。我只是想了解我的应用程序的每个部分是如何消耗资源的。 @Teddy - 线程的大小将取决于线程在做什么。您创建了多少个变量,它们是什么类型,访问静态资源等...除了内存使用情况,您还想监控处理请求所需的实际时间并进行优化。【参考方案6】:看到第 6 点,您可以使用这些工具来查看您的硬件是否成为瓶颈:假设您使用的是 linux,您可以使用 VmStat
查看有关您的 RAM 使用情况的一些统计信息,top
或 @ 987654323@(取决于您的发行版)查看进程对您的 CPU 和 RAM 造成的影响,nload
和 iftop
查看正在消耗网络带宽的内容,iotop
查看正在读取和写入磁盘的内容。
【讨论】:
以上是关于什么决定了同时连接的数量的主要内容,如果未能解决你的问题,请参考以下文章