我想在一个小型机器集群(尽可能小)上同时支持大约 10,000 个 HTTP 客户端。我想在用户使用应用程序时保持与每个客户端的连接,以允许服务器推送更新。
我相信通常建议将异步 IO 用于这些类型的长期连接,以避免大量线程处于空闲状态。但是让线程闲置有什么问题呢?我发现线程模型在精神上更容易使用,但我不想做会让我头疼的事情。我想我必须进行实验,但我想知道是否有人知道以前的这些实验?
我想在一个小型机器集群(尽可能小)上同时支持大约 10,000 个 HTTP 客户端。我想在用户使用应用程序时保持与每个客户端的连接,以允许服务器推送更新。
我相信通常建议将异步 IO 用于这些类型的长期连接,以避免大量线程处于空闲状态。但是让线程闲置有什么问题呢?我发现线程模型在精神上更容易使用,但我不想做会让我头疼的事情。我想我必须进行实验,但我想知道是否有人知道以前的这些实验?
异步 I/O 基本上意味着您的应用程序执行大部分线程调度。与其让操作系统随机挂起您的线程并安排另一个线程,不如让您拥有与 CPU 内核数量一样多的线程,并在最合适的点让步给其他任务——当线程到达 I/O 操作时,这将花费一些时间时间。
从性能的角度来看,上述内容似乎是一个明显的胜利,但异步编程模型在以下几个方面要复杂得多:
另一方面,现代操作系统发生了许多有利的改进和优化,这些改进和优化基本上消除了同步 I/O 编程的性能缺点:
一篇经过上述大部分内容和其他一些观点的经典论文是对我在这里所说的内容的一个很好的补充:
https://www.usenix.org/legacy/events/hotos03/tech/full_papers/vonbehren/vonbehren_html/index.html
您的问题的评论中已经有一些很好的指示。
不使用 10K 线程的原因是这会消耗内存资源,而内存会消耗能量。编程模型是没有争议的,因为坐在客户端连接上的线程不能与想要发布事件的线程相同。
请看一下 websockets 标准和 Servlet 3.0 标准中的异步请求处理模型。所有最近的 Java Web 应用程序服务器现在都实现了它(例如 Glassfish 和 Tomcat),它是您问题的解决方案。
由于缺少您使用的操作系统、JVM 和应用程序服务器,因此无法回答问题本身。但是,您可以自己快速测试它,只需创建一个 servlet 或 JSPThread.sleep(9999999)
并siege -c 10000 ...
对其进行操作。
10,000 个并发 HTTP 客户端......让线程闲置有什么问题?
似乎空闲线程的成本只是为内核结构(几kb)和线程堆栈(512kb-若干mb)分配的内存。但...
显然,你会不时地唤醒你的每一个 n-000 个线程,对吧?那是您支付上下文切换成本的时刻,这可能不是那么小(调用系统调度程序的时间,更多的缓存未命中等)。参见,例如: http ://www.cs.rochester.edu/u/cli/research/switch.pdf
而且您必须非常小心地固定线程,以免影响系统线程。因此,与异步 IO 相比,每个连接线程(阻塞 IO)架构会增加系统的延迟。但是,如果大部分时间几乎所有线程都处于停顿状态,它仍然适用于您的情况。
最后一句话。我们不知道您的线程将在 read() 上被阻塞多少次,以及他们需要做多少工作来处理接收到的数据。将使用哪些硬件、操作系统和网络接口……所以,测试您的系统原型。