低延迟,大规模的消息队列

时间:2009-12-17 04:29:43

标签: performance message-queue xmpp amqp

我正在对Facebook应用程序和云计算时代的大型多人游戏进行一些重新思考。

假设我要在现有开放协议的基础上构建一些东西,并且我想为1,000,000个并发播放器服务,只是为了解决问题。

假设每个玩家都有一个传入消息队列(用于聊天和诸如此类),并且平均有一个传入消息队列(公会,区域,实例,拍卖......),因此我们有2,000,000个队列。玩家将一次收听1-10个队列。每个队列平均每秒可能有1条消息,但某些队列将具有更高的速率和更多的侦听器(例如,级别实例的“实体位置”队列)。我们假设系统排队延迟不超过100毫秒,这对于温和的动作导向游戏来说是可以的(但不是像Quake或Unreal Tournament这样的游戏)。

从其他系统来看,我知道在单个1U或刀片盒上为10,000个用户服务是一个合理的期望(假设没有其他任何昂贵的东西,比如物理模拟或诸如此类的东西)。

因此,使用交叉开关集群系统,客户端连接到连接网关,然后连接到消息队列服务器,我们每个网关有100个用户,有100个网关机器,每个队列服务器有100个消息队列,有100个队列机器。再次,仅适用于一般范围。每台MQ机器上的连接数量很小:大约100,与每个网关通信。网关上的连接数量会更高:客户端为10,100,连接所有队列服务器。 (除此之外,为游戏世界模拟服务器添加一些连接或诸如此类的东西,但我现在试图将它保持分开)

如果我不想从头开始构建这个,我必须使用一些存在的消息传递和/或排队基础结构。我能找到的两个开放协议是AMQP和XMPP。 XMPP的预期用途更像是这个游戏系统所需要的,但开销非常明显(XML,加上冗长的状态数据,以及必须在顶部构建的各种其他通道)。 AMQP的实际数据模型更接近我上面描述的内容,但所有用户似乎都是大型企业级公司,工作负载似乎与工作流程相关,而不是与实时游戏更新相关。

是否有人可以分享您可以分享的这些技术或其实施的白天经验?

5 个答案:

答案 0 :(得分:11)

@MSalters

重新'消息队列':

RabbitMQ的默认操作正是您所描述的:transient pubsub。但用TCP而不是UDP。

如果您想要保证最终交付以及其他持久性和恢复功能,那么您也可以拥有它 - 这是一个选项。这就是RabbitMQ和AMQP的重点 - 只需一个消息传递系统就可以有很多行为。

您描述的模型是DEFAULT行为,它是暂时的,“一劳永逸”,并将消息路由到收件人所在的任何位置。出于这个原因,人们使用RabbitMQ在EC2上进行多播发现。您可以通过单播TCP pubsub获取UDP类型行为。干净,是吗?

Re UDP:

我不确定UDP在这里是否有用。如果您关闭Nagling,那么RabbitMQ单消息往返延迟(客户端 - 代理 - 客户端)的测量值为250-300微秒。请参阅此处以了解与Windows延迟(稍高)http://old.nabble.com/High%28er%29-latency-with-1.5.1--p21663105.html

的比较

我想不出许多需要往返延迟低于300微秒的多人游戏。 TCP可以低于300us。 TCP窗口 比原始UDP更昂贵,但如果你使用UDP更快,并添加自定义丢失恢复或seqno / ack /重新发送管理器,那么这可能会再次降低你的速度。这一切都取决于您的用例。如果你真的真的需要使用UDP和懒惰等等,那么你可以剥离出RabbitMQ的TCP并可能将其拉下来。

我希望这有助于澄清我为Jon的用例推荐RabbitMQ的原因。

答案 1 :(得分:10)

我现在正在构建这样一个系统。

我已经对几个MQ做了大量的评估,包括RabbitMQ,Qpid和ZeroMQ。任何这些应用程序的延迟和吞吐量都足以满足此类应用程序的要求。然而,不好的是在50万或更多队列中间的队列创建时间。在几千个队列之后,Qpid特别严重地降级。为了避免这个问题,您通常必须创建自己的路由机制(总队列数量较少,这些队列中的消费者正在获取他们不感兴趣的消息)。

我当前的系统可能会使用ZeroMQ,但是以相当有限的方式,内部集群。来自客户端的连接使用自定义SIM处理。我使用libev构建的守护进程完全是单线程的(并且显示非常好的扩展 - 它应该能够在一个盒子上处理50,000个连接而没有任何问题 - 我们的sim。滴答率非常低,但是有没有物理学。)

XML(以及XMPP)非常不适合这种情况,因为在绑定I / O之前很久就会处理CPU处理XML,这不是您想要的。我们目前正在使用Google Protocol Buffers,这些似乎非常适合我们的特殊需求。我们还使用TCP进行客户端连接。我曾经有过使用UDP和TCP的经验,而且正如其他人所指出的那样,UDP确实有一些优势,但使用起来稍微困难一些。

希望当我们离启动更近一点时,我将能够分享更多细节。

答案 2 :(得分:5)

Jon,这听起来像是AMQP和RabbitMQ的理想用例。

我不确定为什么你说AMQP用户都是大型企业型公司。超过一半的客户都在“网络”领域,从大型公司到小型公司。 RabbitMQ构建了许多游戏,投注系统,聊天系统,twittery类型系统和云计算基础设施。甚至还有手机应用程序。工作流程只是众多用例中的一种。

我们试着跟踪这里发生的事情:

http://www.rabbitmq.com/how.html(请务必点击del.icio.us上的用例列表!)

请看看。我们在这里提供帮助。请随时发送电子邮件至info@rabbitmq.com或发送电子邮件至twitter(@monadic)。

答案 3 :(得分:3)

FWIW,对于中间结果不重要的情况(如定位信息),Qpid有一个“最后值队列”,只能向订阅者提供最新值。

答案 4 :(得分:2)

我的经验是使用非开放的替代方案BizTalk。我们学到的最痛苦的教训是,这些复杂的系统并不快。正如您从硬件要求中所看到的那样,这直接转化为显着的成本。

出于这个原因,甚至不要接近核心接口的XML。您的服务器群集将每秒解析200万条消息。这可能很容易就是2-20 GB /秒的XML!但是,大多数消息将用于几个队列,而大多数队列实际上是低流量。

因此,设计您的体系结构,以便可以轻松地从COTS队列服务器启动,然后在识别出瓶颈时将每个队列(类型)移动到自定义队列服务器。

此外,出于类似的原因,不要假设消息队列体系结构最适合您的应用程序具有的所有通信需求。以“实例中的实体位置”为例。这是一个经典案例,您希望保证邮件传递。您需要共享此信息的原因是它始终在变化。因此,如果邮件丢失,您不希望花时间恢复邮件。您只需发送受影响实体的旧位置。相反,您需要发送该实体的当前位置。技术方面,这意味着您需要UDP,而不是TCP和自定义的丢失恢复机制。