Java大型多人游戏服务器可扩展性

Wha*_*mes 10 java concurrency multithreading garbage-collection tcp

我为Android创建了一款名为The Infinite Black的大型多人在线游戏:https: //market.android.com/details?id = theinfiniteblack.client

在我天真的时候,我预计每月约有1,000名玩家的适度增长率,并且需要管理大约20个实时TCP/IP客户端.

该游戏出乎意料地爆炸性增长,一周内有超过40,000名新用户,并且一次平均有大约300个实时连接,并呈指数级增长.

服务器体系结构包括每个连接2个线程(阻塞读/写),一个ServerSocket线程产生新客户端,以及一个控制器线程,用于轮询每个客户端以获取新操作,将其应用于游戏世界,然后在将数据刷新时将数据刷回完成.

服务器是用Java构建的,我不是很精通,特别是在像这样的高压力情况下.在内存和线程管理方面,C#真的让我很烦恼.

为了达到目的......我刚刚订购了两个非常强大的系统作为专用游戏服务器运行,并希望最大限度地利用资源.有关Java资源配置的大量信息已被证明具有误导性,不正确或过时.

我目前使用-Xss512k作为我的启动参数,并且理解这决定了每个线程的堆栈大小分配,但我不完全理解它可能带来的所有内容.有什么工具或方法可以告诉我,如果我超出标记并可以缩小它?我应该考虑哪些其他命令行参数?

新服务器拥有16GB的RAM和i7-2600K Sandy Bridge 3.4GHz处理器:配置中有哪些选项可以尽可能地利用这一优势?我的目标是每台服务器一次1,200个在线客户端(2,400个线程).

我应该关注哪些意想不到的陷阱和问题?

我已经阅读了关于最大线程数的极其矛盾的故事:如果我试图推动2,400个活动线程,事情会崩溃吗?

Java似乎不是为这类任务而设计的.我应该考虑将服务器迁移到另一种语言吗?

我目前在Eclipse中运行调试模式的服务器,而它正在开发中(呃..)

这是我的Eclipse .ini配置:

--launcher.XXMaxPermSize 256M

-Xms256m

-Xmx1024m

Pet*_*rey 8

你还没有说清楚你怀疑的来源.

Plurk Comet:与Netty处理100,000多个并发连接(2009)

在1999年,我部署了一个Java Web服务器,每小时处理40,000个黄页搜索查询(服务器有400 MHz CPU),2004年我开发了一个Java应用程序,每个服务器处理8000个并发连接(在双1.2 GHz Sparc服务器上)有六个网关服务器和一个主服务器来控制它们并集中事件.

您的个人资料可能会有所不同,但我可以说Java在C#发布之前支持大容量Web服务器.

就个人而言,每台服务器不会有超过10,000个并发连接,但这只是一个经验法则,可能不再适用.您可以在一个JVM中拥有32,000个线程.在Linux上它并没有超出这个范围.但是,我会在单个服务器上安装多个网关JVM,以最大限度地缩短GC的完整时间(最小化完整GC时间的最佳方法是丢弃更少的垃圾,但这可能需要更多的努力)

新服务器拥有16GB的RAM和i7-2600K Sandy Bridge 3.4GHz处理器:配置中有哪些选项可以尽可能地利用这一优势?我的目标是每台服务器一次1,200个在线客户端(2,400个线程).

我无法想象为什么这会成为一个问题.

我应该关注哪些意想不到的陷阱和问题?

认为您需要转换每个可能的命令行参数,因为您可能会将所有这些参数都取消.如果你有4个网关JVM,每个JVM有300个连接,这可以使用所有内存,你甚至不需要指定-Xmx设置.

Java似乎不是为这类任务而设计的.我应该考虑将服务器迁移到另一种语言吗?

你最好问自己为什么相信这一点.你有一个问题应该是简单的解决或怀疑可能是也可能没有根据.

这是我的Eclipse .ini配置:

你如何配置eclipse没有限制如何设置从eclipse运行的程序.

BufferedOutputStream适用于大多数应用程序,并且可能适用于JVM中多达1000个连接.然而,Java 1.4(2002)增加了NIO,这对于将系统扩展到10,000个连接以及更高的连接来说更轻.

BTW:我在2003年开发的服务器基于NIO调度程序,但除非你使用像Netty这样的标准库,否则它非常复杂.

从那以后,我使用每个连接模型的单个线程来成功阻止NIO.我相信这比使用调度程序更容易管理,并且具有更低的延迟特性.我有一个监视器线程,它定期检查连接在写入时是否阻塞,如果是,则关闭它们.我不相信每个连接需要两个线程,但我不相信它会对您的情况产生影响,因为每个服务器都没有足够的连接.

正如glowcoder建议您考虑使用UDP来获得不太重要的广播信息吗?


cor*_*iKa 4

在 Java 中,每个线程将在堆栈上占用与任何其他线程相同的内存量。这意味着你的主线程,假设它有 32k 的保留大小(我认为这是默认值)将与你的通信线程的保留大小相同(如果你考虑一下,可能只需要 1k!)这就是 Java 的原因想出了nio - 所以你不需要每个连接一个线程。

我们以 1g RAM 为例。每个线程有 32k 内存,假设我们有一半内存用于堆栈,一半内存用于堆,则最终可用于堆栈的内存为 512。这为我们提供了 16,384 个线程的空间。这也意味着我们的线程调度程序必须处理 16,384 个线程。这大大增加了其中一个线程饥饿的机会。现在,如果一个人挨饿了,那么他就很糟糕;如果main挨饿了,那就糟糕了……每个人!

有了 nio,你就有了……两个线程。主要,沟通。(实际上,您甚至可以在没有通信线程的情况下做到这一点......)。现在实际上你可能有更多的东西,因为你有一个游戏循环等等。但 10 个线程仍然比 16k 线程更容易正确调度!

Nio 学习起来不一定直观,但非常值得。

如果您不打算使用 nio,我会考虑的一件事是每个连接只有 1 个线程而不是两个。您不需要第二个线程来进行写入:您可以拥有一个带有队列的线程,并让它为所有客户端执行所有写入操作。暂时这将使您的吞吐量至少增加一倍。