每个连接模型的Java线程与NIO

时间:2011-01-20 20:20:19

标签: java multithreading asynchronous nio nonblocking

非阻塞Java NIO是否仍然比每个连接异步套接字的标准线程慢?

另外,如果你每个连接使用线程,你只是创建新线程还是使用非常大的线程池?

我正在用Java编写一个MMORPG服务器,它应该能够在足够强大的硬件下轻松扩展10000个客户端,尽管最大客户端数量是24000(我相信每个连接模型的线程无法达到,因为Java中的15000线程限制)。 从一篇三年前的文章中,我听说用每个连接模式的线程阻止IO仍然比NIO快25%(即本文档http://www.mailinator.com/tymaPaulMultithreaded.pdf),但是在这一天仍然可以实现相同的目标吗?从那以后Java发生了很大变化,我听说在比较现实生活场景时结果是有问题的,因为使用的VM不是Sun Java。 另外,因为它是一个MMORPG服务器,许多并发用户互相交互,所以使用同步和线程安全实践会降低性能,以至于为10000个客户端提供服务的单线程NIO选择器会更快吗? (所有工作都不必在带有选择器的线程上处理,它可以在工作线程上处理,就像MINA / Netty的工作方式一样)。

谢谢!

7 个答案:

答案 0 :(得分:20)

NIO的好处应该是一粒盐。

在HTTP服务器中,大多数连接都是保持连接的连接,它们大多数时间都处于空闲状态。为每个人预先分配一个线程将浪费资源。

对于MMORPG来说,情况非常不同。我猜连接总是忙于接收用户的指令并向用户发送最新的系统状态。大多数时候需要一个线程来进行连接。

如果您使用NIO,则必须不断为连接重新分配线程。对于简单的每线程固定线程解决方案,它可能是一个较差的解决方案。

默认的线程堆栈大小非常大(1/4 MB?),这是为什么只能有限的线程的主要原因。尝试减少它,看看你的系统是否可以支持更多。

但是,如果您的游戏确实非常“忙碌”,那么您最需要担心的是CPU。 NIO与否,在机器上处理成千上万的超级游戏玩家真的很难。

答案 1 :(得分:12)

实际上有3个解决方案:

  1. 多线程
  2. 一个帖子和NIO
  3. 解决方案1和2都是相同的 时间
  4. 有关的性能最好的事情是让线程和多路复用网络事件的一个小的,有限数目的到这些线程与NIO新消息进来在网络上。


    将NIO用于一个线程是一个坏主意,原因如下:

    • 如果您有多个CPU或核心,那么您将暂停资源,因为如果您只有一个线程,您一次只能使用一个核心。
    • 如果您必须阻止出于某种原因(也许做一个磁盘访问),你的CPU在空闲时你可以处理其他连接,而你等待磁盘。

    每个连接一个线程是一个坏主意,因为它不能扩展。让我们说:

    • 10 000个连接
    • 每个2核的2个CPU
    • 在任何给定时间只会阻止100个线程

    然后你可以计算出你只需要104个线程。更多,你浪费资源管理你不需要的额外线程。管理10000个线程需要大量的簿记。这会让你慢下来。


    这就是您将这两种解决方案结合起来的原因。此外,请确保您的VM使用最快的系统调用。每个操作系统都有自己独特的系统调用,用于高性能网络IO。确保您的VM使用最新且最好的。我相信这是Linux中的epoll()。

      

    另外,如果你要使用   每个连接的线程,你愿意吗?   创建新线程或你会使用   非常大的线程池?

    这取决于您希望花多少时间进行优化。最快的解决方案是在需要时创建线程和字符串等资源。然后让垃圾收集在你完成它们时声明它们。您可以通过拥有一个资源池来提升性能。您不需要创建新对象,而是要求池中的一个,并在完成后将其返回池中。这增加了并发控制的复杂性。这可以使用诸如non-blocking algorithms之类的高级并发算法进一步优化。新版本的Java API为您提供了一些新功能。您可以在一个程序中度过余生,进行这些优化。对于您的特定应用程序,最佳解决方案可能是一个值得自己发布的问题。

答案 2 :(得分:9)

如果您愿意在功能强大的硬件上花费任何金钱,那么为什么要将自己限制在一台服务器上。谷歌不使用一台服务器,他们甚至不使用一个服务器数据中心。

一个常见的误解是NIO允许非阻塞IO,因此它是唯一值得基准测试的模型。如果您对阻止NIO进行基准测试,则可以比旧IO快30%。即如果您使用相同的线程模型并仅比较IO模型。

对于复杂的游戏,在达到10K连接之前,你更有可能耗尽CPU。同样,有一个水平扩展的解决方案更简单。然后,您无需担心可以获得多少连接。

有多少用户可以合理地互动? 24?在这种情况下,您有1000个独立的组进行交互。您将不会在一台服务器中拥有这么多核心。

您打算在服务器上花费多少钱?您可以以低于5000英镑的价格购买带有64 GB内存的12核服务器。如果您在此服务器上放置2500个用户,则每个用户花费2英镑。

编辑:我有一个参考http://vanillajava.blogspot.com/2010/07/java-nio-is-faster-than-java-io-for.html,这是我的。 ;)我是由Java Networking GURU的人审核过的,并且大致同意他所发现的内容。

答案 3 :(得分:3)

如果您有繁忙的关联,这意味着他们会不断向您发送数据并将其发回,您可以将non-Blocking IOAkka结合使用。

  

Akka是一个开源工具包和运行时,简化了JVM上并发和分布式应用程序的构建。 Akka支持多种编程模型以实现并发,但它强调基于actor的并发性,其灵感来自Erlang。 Java和Scala都存在语言绑定。

Akka的逻辑是非阻塞的,因此非常适合异步编程。使用Akka Actors,您可以删除Thread overhead
但如果您的套接字流更频繁地阻止,我建议将Blocking IOQuasar

结合使用
  

Quasar是一个开源库,用于简单,轻量级的JVM并发,它在JVM上实现真正的轻量级线程(AKA光纤)。类星体光纤的行为与纯Java线程一样,除了它们几乎没有内存和任务切换开销,因此您可以在单个JVM中轻松生成数十万个光纤 - 甚至数百万个光纤。 Quasar还为Go语言提供的光纤间通信提供了通道,并配有通道选择器。它还包含演员模型的完整实现,紧密模仿Erlang。

Quasar的逻辑阻塞,所以你可能会产生,比如在不同的连接上等待24000个光纤。关于Quasar的一个积极观点是,纤维可以很容易地与普通螺纹相互作用。此外,Quasar还与热门图书馆(例如Apache HTTP clientJDBCJersey等)进行了集成,因此您可以在项目的许多方面使用光纤。 您可能会在这两个框架here之间看到一个很好的比较。

答案 4 :(得分:1)

你可能会从前Sun赞助的项目中得到一些灵感,现在名为Red Dwarf。 http://www.reddwarfserver.org/的旧网站已关闭 Github救援:https://github.com/reddwarf-nextgen/reddwarf

答案 5 :(得分:1)

正如大多数人所说,在达到10k并发用户之前,服务器必然会被锁定在CPU使用率中,我认为考虑到以下事实,我最好使用线程阻塞(N)IO方法。对于这个特定的MMORPG,每个玩家每秒获得几个数据包的情况并不少见,如果要使用一个选择器,可能会陷入困境。

Peter提出了一个有趣的观点,即阻止NIO比旧库更快,而无可争辩地提到,对于繁忙的MMORPG服务器,由于每个播放器接收了多少指令,因此最好使用线程。我不会指望太多的玩家在这个游戏上闲置,所以对我来说,拥有一堆非运行线程应该不是问题。我已经意识到,即使使用基于NIO的框架,仍然需要同步,因为它们使用多个工作线程同时运行来处理从客户端接收的数据包。上下文切换可能证明是昂贵的,但我会尝试这个解决方案。重构我的代码相对容易,这样如果我发现存在瓶颈,我就可以使用NIO框架。

我相信我的问题已得到解答。我会等一下,以便从更多人那里获得更多的洞察力。谢谢你的所有答案!

编辑:我终于选择了我的行动方案。我实际上是优柔寡断,决定使用JBoss Netty并允许用户使用类在oio或nio之间切换

org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory;

很好,Netty支持两者!

答案 6 :(得分:0)

如果您进行客户端网络调用,则很可能只需要普通套接字io。

如果要创建服务器端技术,则NIO将帮助您将网络io部分与实现/处理工作分开。   用于网络IO的IO线程配置为1或2。工作线程用于实际的处理部分(根据机器功能,范围从1到N)。