[英]One thread per client. Doable?
我正在编写一个Java服务器,它使用普通套接字来接受来自客户端的连接。 我正在使用相当简单的模型,其中每个连接在阻塞模式下都有自己的线程读取。 伪代码:
handshake();
while(!closed) {
length = readHeader(); // this usually blocks a few seconds
readMessage(length);
}
cleanup();
(线程是从Executors.newCachedThreadPool()
创建的,因此启动它们不会有任何重大开销)
我知道这是一个天真的设置,如果线程是专用的OS线程,它不会很好地扩展到许多连接。 但是,我听说Java中的多个线程可以共享一个硬件线程。 真的吗?
知道我将在Linux上使用Hotspot VM,在具有8核和12GB RAM的服务器上,你认为这个设置适用于成千上万的连接吗? 如果没有,有哪些替代方案?
这可能会扩展到数千个客户端。 但究竟有多少十万是下一个问题。
一种常见的替代方法是使用java.nio
包中的Selectors和非阻塞I / O.
最后,您会遇到在群集配置中设置服务器是否有用的问题,以平衡多个物理机器上的负载。
这可以很好地扩展到数百个连接,而不是数千个连接。 一个问题是Java线程也需要相当多的堆栈(例如256K),并且操作系统在调度所有线程时会遇到问题。
查看Java NIO或framworks,它将帮助您更轻松地开始复杂的工作(例如Apache Mina)
为了在处理许多套接字时具有良好的性能,通常使用一种select
方法,即Unix API处理需要许多资源的单线程多套接字应用程序。
这可以通过java.nio
包来完成,该包具有一个Selector
类,它基本上可以通过所有打开的套接字并在新数据可用时通知您。
您在一个Selector
注册所有已打开的流,然后您可以从一个线程处理所有这些流。
您可以在此处获得有关教程的其他信息
试试Netty 。
“每个请求一个线程”模型是大多数Java应用服务器编写的方式。 您的实施可以像他们一样扩展。
线程并不像以前那么昂贵,因此“普通”的IO实现可以说明问题。 但是,如果您正在考虑扩展到数千或更高,那么可能值得研究一些更复杂的东西。
java.nio包通过提供套接字多路复用/非阻塞IO来解决这个问题,它允许您将多个连接绑定到一个Selector。 然而,由于多线程和非阻塞方面,这种解决方案比简单的阻塞方法更难实现。
如果你想追求简单IO以外的东西,那么我建议你看一下那里的优质网络抽象库。 根据个人经验,我可以推荐Netty ,它可以为您完成大部分繁琐的NIO处理。 然而它确实有一点学习曲线但是一旦你习惯了基于事件的方法,它就会非常强大。
我建议它更多地取决于服务器在处理消息时正在做什么。 如果它相对轻量级,那么您的机器规格应该易于处理仅仅处理数千个这样的过程的连接。 成千上万是另一个问题,但你只需要在同一网络上的两台机器实际上对它进行实验测试并获得明确的答案。
为什么要自己动手? 您可以使用带有servlet,消息队列或ZeroMQ的servlet容器。
我认为更好的方法是不自己处理线程。 创建一个池(ThreadExecutor或其他一些东西)和简单的调度工作到您的池。
当然,我认为异步I / O会使它更好更快,但会帮助你解决套接字和网络问题。 只要。 当您的线程因I / O而阻塞时,JVM将使其进入休眠状态并更改另一个线程,直到阻塞I / O返回。 但这只会阻止线程。 您的处理器将继续运行并开始处理其他线程。 因此,减去创建线程的时间,使用I / O的方式对模型的影响不大。 如果您不创建线程(使用池),问题就解决了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.