【问题标题】:Apache HTTP Client: build simulator using multithreaded environmentApache HTTP Client:使用多线程环境构建模拟器
【发布时间】:2014-12-05 22:08:08
【问题描述】:

我正在构建一个独立的 java 应用程序来在系统上生成负载,模拟现实世界的条件。

应用程序是多线程的,使用并发框架生成大量线程池,每个线程都运行“会话”。当会话完成时,runnable 结束并且线程返回到调度程序池。每个“会话”包含以下内容:

  • 生成 HTTP PUT #1 到服务器
  • 等待 x 秒(在逻辑限制内随机)
  • 生成 HTTP PUT #2 到服务器
  • 生成 HTTP PUT #3 到服务器
  • 等待 y 秒(在逻辑限制内随机)
  • 生成 HTTP PUT #4 到服务器
  • 生成 HTTP PUT #5 到服务器

每个会话总共占用大约 2 分钟

并发池创建的每个线程都维护一个连接(一个 HTTPClient),该连接被后续会话重用。每次请求后,都会按照建议调用 HttpRequest.releaseConnection()。

一切都很好。但也许太好了。

虽然保持连接打开并释放它们可以提供最佳性能,因为我正在构建一个模拟器,所以我真的不想要最佳性能。我想模拟次优性能。我希望服务器必须在每个会话上建立连接。
我想在每个会话开始时创建连接(嵌入在 HTTP 客户端中)并在会话结束时关闭它。

为此,我只需在会话结束时关闭 HttpClient 并将其变量设置为 null(都在 finally 子句中)。当应用程序会话线程开始一个新会话时,如果客户端为空,它会使用 HttpClientBuilder 构建一个新会话。但是,当我这样做时,会出现各种连接池错误,这些错误会破坏模拟。

如上所述,是否有一种正确的方法可以使用 Apache HttpClient 以次优方式建立连接?有点疯狂的问题,但却是一个真实的问题。

【问题讨论】:

    标签: java multithreading apache-httpclient-4.x java.util.concurrent


    【解决方案1】:

    您可以使用构建器的setConnectionReuseStrategy 切换池内连接的重用。 DefaultConnectionReuseStrategy 将尽可能重用连接,但NoConnectionReuseStrategy 将关闭所有返回池的连接。

    我反向使用了这些连接重用策略:在生产中没有设置重用(以确保适当的负载平衡 - 每个新连接都指向一个健康的服务器),但在测试期间我不得不切换回默认的重用策略,因为测试创建了如此多的连接,以至于测试机器很快用完了端口(使用本地端口后,操作系统将端口保持在等待/冷却室,这是 TCP 协议的一部分)。好消息是,对于连接重用策略的这一设置,测试代码仅与生产代码不同。

    请注意,连接池和不重复使用连接的组合仍然有其目的:池将阻止超过其最大允许大小的打开连接。例如。如果应用程序决定同时打开 100 个连接,并且池的最大大小为 30,则池将让其他 70 个连接的其他请求等待,直到连接返回。这是使客户端表现良好并防止它们使服务器过载的好方法。

    【讨论】:

    • 是的,这就是我正在寻找的,模拟基于会话的连接重用的“正确方法”。在第一次 POST 之后,我在 Thread 的 HttpContext 中设置了一个名为“session”的属性。我在发送最后一条消息后将其删除。然后我实现并配置我的 ClientBuilder 以使用自定义 ConnectionReuseStrategy 如果找到属性,则返回 true,否则返回 false。这似乎没有我之前的尝试看到的错误。第一个请求使用新连接,第二个到第五个不使用。
    【解决方案2】:

    几个月前我也遇到了这个问题。当您调用HttpRequest.releaseConnection() 时,连接被池化并且不会立即关闭。当您开始创建新的 HttpClients 时,您也停止使用这些连接池并在每次需要请求时开始创建新的 TCP 连接,这就是导致问题的原因。如果您有多个线程在短时间内创建和释放连接,那么 Java(甚至是底层 OS 层)开始抛出错误,根据您的 cmets,我认为这是发生在您身上的错误。

    这是我当时尝试并似乎降低了此类错误发生率的简短列表:

    1. 将 TCP 连接超时值设置为低值(例如 5 秒)。我在 OSX 上使用 Java 1.7.0 运行我的代码,这让事情变得更好。后来我停止使用 HttpClient 并切换到 JerseyClient 并且低超时也产生了积极的影响。
    2. 如果您使用的是 OSX/Linux,请使用 ulimit 命令增加最大文件描述符数。这不会使连接更快地关闭,但似乎可以让您保持更多连接打开,从而延迟问题。
    3. 不要让单个进程具有多个进程(例如,1 个进程具有 500 个线程),而是尝试生成多个线程较少的子进程(例如,5 个进程,每个进程具有 100 个线程)。我注意到杀死子进程有助于关闭连接。

    当时我还不得不将测试代理分发到多个主机上并使用Grinder 来同步它们。取决于您尝试测试服务器的并发连接数,但这可能是最好的方法。

    【讨论】:

      猜你喜欢
      • 2014-02-17
      • 2019-01-28
      • 1970-01-01
      • 1970-01-01
      • 2012-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-10
      相关资源
      最近更新 更多