我尝试创建连接到我的 glassfish websocket 服务器的大约 5000 个并发客户端(不停止从服务器向客户端发送数据)。 (CPU:双核,8 GB 内存)
连接大约 2500 个客户端后,连接时间约为 67(!)秒,由于 TimeOutException
,我无法连接更多客户端。
一些事实:
- 线程池最大大小设置为 12.000。
- 在第一次出现 TimeoutException 时,我有 2500 个客户端和大约 2450 个线程。因此,我们在这里讨论每个连接一个线程。
- 这不是内存问题!
然后在 Node.js 和 golang 中编写了两个简单的 Websocket 代理服务器来处理 websocket 连接。代理服务器和 glassfish 服务器之间的数据交换发生在简单的 Websocket 连接上。
现在我能够毫无问题地创建超过 5000 个并发客户端。我在 Wildfly 8 和 Tomcat 8 上遇到了同样的问题。 这是评价:
现在我的问题。
Tyrus是 glassfish 中 Websocket 协议(protocol)的实现,并在底层使用 java.nio
库实现非阻塞 I/O。
那么为什么它的可扩展性这么差呢?或者为什么可扩展性如此不同。我的意思是我认为 java.nio
附言只是安排开销?
编辑:如何重现问题
用于创建和连接客户端的客户端软件与 Websocket 服务器位于不同的 PC 上。
最佳答案
这个问题有很多可能的答案包括:
也许 Tyrus 真的不能很好地扩展。
也许您没有正确使用它;也就是说,您的代码正在做一些导致 Tyrus 表现不佳的事情。
也许您正在“比较苹果和橘子”;即您的测试正在比较不同的事物。
可能是内存问题。你有什么证据证明它不是?
可能是多种原因造成的。
遗憾的是,您没有提供任何具体信息来帮助我们区分可能的原因和不太可能的原因。
根据您在更新/评论中报告的内容,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/