尽管使用了 java.NIO,但 Java Websockets 的可扩展性很差

标签 java node.js multithreading go websocket

我尝试创建连接到我的 glassfish websocket 服务器的大约 5000 个并发客户端(不停止从服务器向客户端发送数据)。 (CPU:双核,8 GB 内存)

连接大约 2500 个客户端后,连接时间约为 67(!)秒,由于 TimeOutException,我无法连接更多客户端。

一些事实:

  • 线程池最大大小设置为 12.000
  • 在第一次出现 TimeoutException 时,我有 2500 个客户端和大约 2450 个线程。因此,我们在这里讨论每个连接一个线程。
  • 这不是内存问题!

然后在 Node.jsgolang 中编写了两个简单的 Websocket 代理服务器来处理 websocket 连接。代理服务器和 glassfish 服务器之间的数据交换发生在简单的 Websocket 连接上。

现在我能够毫无问题地创建超过 5000 个并发客户端。我在 Wildfly 8 和 Tomcat 8 上遇到了同样的问题。 这是评价:

avaluation

现在我的问题。 Tyrus是 glassfish 中 Websocket 协议(protocol)的实现,并在底层使用 java.nio 库实现非阻塞 I/O。

那么为什么它的可扩展性这么差呢?或者为什么可扩展性如此不同。我的意思是我认为 java.nio

没有优势

附言只是安排开销?


编辑:如何重现问题

用于创建和连接客户端的客户端软件与 Websocket 服务器位于不同的 PC 上。

  1. 启动 glassfish 简单 echo websocket 服务器。大约有 76 个活跃的 glassfish 线程。 GlassFish-2000-connected-And-Idle
  2. 现在连接 2000 个客户端而不启动任何通信,只连接到服务器 - 空闲模式。就我而言,这样做没有问题。由于所有客户端都已连接,因此大约有 80 个 Activity 线程。几乎没有变化。
  3. 使用 Timer 让所有 2000 个客户端同时开始与 websocket 服务器通信。您会注意到线程数量现在约为 2019 年。响应时间约为 6.5 秒。 GlassFish-2000-connected-And-Active
  4. 最后尝试连接接下来的 500 个客户端。将发生第一个 TimeoutException。只会连接少数客户端。
  5. 同时停止通信。 Stop communication

最佳答案

这个问题有很多可能的答案包括:

  1. 也许 Tyrus 真的不能很好地扩展。

  2. 也许您没有正确使用它;也就是说,您的代码正在做一些导致 Tyrus 表现不佳的事情。

  3. 也许您正在“比较苹果和橘子”;即您的测试正在比较不同的事物。

  4. 可能是内存问题。你有什么证据证明它不是?

  5. 可能是多种原因造成的。

遗憾的是,您没有提供任何具体信息来帮助我们区分可能的原因和不太可能的原因。


根据您在更新/评论中报告的内容,Tyrus 似乎为每个 WebSocket 连接使用一个线程,但其他人使用更具可扩展性的方法。

使用 NIO 并不一定意味着非阻塞 I/O。


documentation对于 WebSocket API 的 Tomcat 7 实现,它是这样说的:

The Java WebSocket 1.0 specification requires that callbacks for asynchronous writes are performed on a different thread to the thread that initiated the write. Since the container thread pool is not exposed via the Servlet API, the WebSocket implementation has to provide its own thread pool. This thread pool is controlled by the following servlet context initialization parameters:

  • org.apache.tomcat.websocket.executorCoreSize: The core size of the executor thread pool. If not set, the default of 0 (zero) is used. Note that the maximum permitted size of the executor thread pool is hard coded to Integer.MAX_VALUE which effectively means it is unlimited.
  • org.apache.tomcat.websocket.executorKeepAliveTimeSeconds: The maximum time an idle thread will remain in the executor thread pool until it is terminated. If not specified, the default of 60 seconds is used.

这暗示了为什么在 Tyrus 中创建线程,并且暗示 Tomcat 可能比 Glassfish 上的 Tyrus 更具可扩展性。 (我也会在 Grizzly 上尝试 Tyrus。)

关于尽管使用了 java.NIO,但 Java Websockets 的可扩展性很差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32396647/

相关文章:

java - OWLAPI : Parser not found if run from Jar

c++ - EvtSubscribe 和线程

node.js - 在 Cloud 9 IDE 中更新 node.js 版本

node.js - 在 package.json 中使用私有(private) git 存储库部署 Google App Engine

javascript - 如何在 Express Nodejs 中更改本地范围内的全局 var 值

c++ - 未处理的异常 : Corrupted heap and access violation reading memory location

java - libgdx - 如何访问 postRunnable

java - 使用 xml 属性和自定义字体将 TextView 设置为粗体字体(不起作用)

java - 使用自签名证书的 gradle Nexus

java - JFrame 将不会显示面板/按钮(单独的类)- java