尽管使用了java.NIO,Java Websockets的可扩展性仍然较差。

3
我尝试创建约5千个并发客户端(从服务器到客户端的非停止数据发送)连接到我的glassfish websocket服务器。(CPU:双核,8GB RAM)
在连接了大约2500个客户端后,连接时间约为67秒,并且由于“TimeOutException”,我无法连接更多客户端。
一些事实:
- 线程池最大大小设置为12,000。 - 在第一个TimeoutException时,我有2500个客户端和约2450个线程。因此,我们在这里讨论每个连接一个线程。 - 这不是内存问题!
然后,我编写了两个简单的Websocket代理服务器,在Node.js和golang中处理Websocket连接。代理服务器与glassfish服务器之间的数据交换通过简单的Websocket连接进行。
现在,我能够创建超过5千个并发客户端而没有任何问题。 Wildfly 8和Tomcat 8也遇到了同样的问题。以下是评估:

avaluation

现在我的问题是,Tyrus 是在glassfish中实现Websocket协议的,并在底层使用java.nio库进行非阻塞I/O。那么为什么它的可扩展性如此之差呢?或者说为什么可扩展性如此不同。我的意思是我看不到java.nio的任何优势。附注:只是调度开销吗?

编辑:如何重现问题

创建和连接客户端以及Websocket服务器的客户端软件位于不同的计算机上。

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

那么你的测量结果可比较吗?你在使用Node.js和Golang实现时有2450个线程吗? - Kayaman
@Kayaman 不是因为代理服务器和真实服务器之间只有一个连接。而是因为Tyrus使用非阻塞IO,而Node.js也使用它。为什么可扩展性如此不同呢?我的意思是我看不到java.nio的任何优势。 - dieter
3
由于您没有提供任何实际信息,我将为您提供一个“您可能正在做错某些事情”的答案。 - Kayaman
那Node.js和Go版本呢?它们也会生成多个线程吗? - Stephen C
@StephenC Node.js和Go版本只生成一些线程:THREAD_COUNT = CPU_COUNT - dieter
1个回答

2

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

  1. 也许 Tyrus 真的不适合扩展。

  2. 也许您没有正确使用它;即您的代码正在执行某些导致 Tyrus 性能不佳的操作。

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

  4. 也许这确实是一个内存问题。您有什么证据证明它不是吗?

  5. 也许这是由多种原因引起的。

不幸的是,您没有提供任何具体信息,使我们能够区分可能和不太可能的原因。


根据您在更新/评论中所报告的内容,似乎Tyrus为每个WebSocket连接使用一个线程,而其他人使用了更可扩展的方法。
使用NIO并不一定意味着非阻塞I/O。
在Tomcat 7实现WebSocket API的文档中,它说:
Java WebSocket 1.0规范要求异步写入的回调在启动写入的线程上运行不同的线程。由于容器线程池未通过Servlet API暴露,WebSocket实现必须提供自己的线程池。此线程池由以下servlet上下文初始化参数控制:
org.apache.tomcat.websocket.executorCoreSize:执行程序线程池的核心大小。如果未设置,则使用默认值0(零)。请注意,执行程序线程池的最大允许大小已硬编码为Integer.MAX_VALUE,这实际上意味着它是无限的。
org.apache.tomcat.websocket.executorKeepAliveTimeSeconds:空闲线程在执行程序线程池中保持的最长时间,直到终止线程。如果未指定,则使用默认值60秒。
这暗示了Tyrus创建线程的原因,并暗示使用Tomcat在Glassfish上比Tyrus更具可扩展性。(我也会尝试在Grizzly上使用Tyrus。)

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