我为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内存和i7-2600K Sandy Bridge 3.4GHz处理器:配置中有哪些选项可以尽可能地利用这一优势?我的目标是每台服务器一次1,200个在线客户端(2,400个线程)。
我应该关注哪些意外的陷阱和问题?
我已经阅读了关于最大线程数的极其矛盾的故事:如果我试图推动2,400个活动线程,事情会崩溃吗?
Java似乎不是为这类任务而设计的。我应该考虑将服务器迁移到另一种语言吗?
我目前在Eclipse的调试模式下运行服务器,而它正在开发中(呃..)
这是我的Eclipse .ini配置:
- launcher.XXMaxPermSize 256M
-Xms256m
-Xmx1024m
答案 0 :(得分:8)
你还没有说清楚你怀疑的来源。
Plurk Comet: Handling 100,000+ Concurrent Connections with Netty (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内存和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来获得不太重要的广播信息吗?
答案 1 :(得分:4)
在Java中,每个线程将在堆栈中占用与任何其他线程相同的内存量。这意味着你的主线程,假设它有一个32k的保留大小(我认为是默认的)将与你的通信线程保持相同的大小(如果你考虑它可能只需要1k!)这就是为什么Java提出了nio - 所以你不需要每个连接一个线程。
让我们给出1g的RAM示例。每个线程32k,假设我们有一半的内存用于堆栈,一半用于堆,我们最终得到512可用于堆栈。这为我们提供了16,384个线程的空间。这也意味着我们的线程调度程序必须处理16,384个线程。这大大增加了其中一个线程被饿死的可能性。现在,如果一个人饿死了,那就很难成为他了;如果main
被饿死了,那就太糟糕了......
使用nio,你有......两个线程。主要和沟通。 (你甚至可以在没有通信线程的情况下实现它,实际上......)。实际上你可能有更多的东西,因为你有一个游戏循环等。但仍然有10个线程比16k线程更容易安排正确!
Nio不一定非常直观,但它非常值得。
如果你不打算使用nio,我会考虑的一件事是每个连接只有1个线程而不是2个。您不需要第二个用于编写:您可以拥有一个带队列的线程,并让它为所有客户端执行所有写操作。这至少会使你的吞吐量翻倍。
答案 2 :(得分:-2)
您不能在节点的负载中考虑线程数量。 1) 如果您的游戏扩展到数百万用户,则需要通过注册表负载平衡的服务器集群
2)每个节点必须是低延迟意味着每个传入的播放器消息和世界更新计算(1滴答)必须在毫秒内完成。非常可行。无需为每个节点配置怪物。
3)每秒拨打30次
=>你可以在一个节点上同时拥有数千个玩家,并通过基础设施前面的注册表确保玩家连接到最好的ping延迟游戏服务器,并通过区域分割将10个thousansd扩展到数百万个。
这个模式在每个节点上实时游戏中加载了10 000个同时玩家,在回合制游戏中每个节点加载了300,000个。
瓶颈通常是IO。使用SSD进行数据库存储。
Java不是问题。 2400线程是个问题。你可以用花费的循环时间来解决问题,并且必须考虑毫秒级滴答循环。
HTH
Nuggeta admin - 100% Free high load multiplayer java game server