性能-低延迟,大规模消息排队

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

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

假设每个玩家都有一个传入消息队列(用于聊天和其他操作),并且平均而言,还有一个传入消息队列(行会,区域,实例,拍卖等),因此我们有2,000,000个队列。 玩家将一次收听1-10个队列。 每个队列平均每秒可能有1条消息,但是某些队列将具有更高的速率和更多的侦听器(例如,级别实例的“实体位置”队列)。 假设系统排队等待时间不超过100毫秒,对于轻度面向动作的游戏(但Quake或Unreal Tournament等游戏则不行)是可以的。

从其他系统来看,我知道在单个1U或刀片服务器上为10,000个用户提供服务是一个合理的期望(假设没有其他昂贵的活动在进行,例如物理模拟或其他)。

因此,在纵横制集群系统中,客户端连接到连接网关,而连接网关又连接到消息队列服务器,我们将获得100个网关计算机的每个网关10,000个用户,以及100个队列计算机的每个队列服务器20,000个消息队列。 再次,仅用于一般作用域。 每台MQ机器上的连接数将很少:大约100个,可以与每个网关进行通信。 网关上的连接数会更高:客户端为10,100 +与所有队列服务器的连接。 (最重要的是,添加一些用于游戏世界模拟服务器的连接或其他连接,但我现在暂时将其分开)

如果我不想从头开始构建它,则必须使用一些现有的消息传递和/或排队基础结构。 我可以找到的两个开放协议是AMQP和XMPP。 XMPP的预期用途有点类似于此游戏系统所需的用途,但是开销非常明显(XML,加上详细的状态数据,以及必须建立在其上的各种其他通道)。 AMQP的实际数据模型与我上面描述的更为接近,但是所有用户似乎都是大型企业型公司,并且工作负载似乎与工作流相关,而不与实时游戏更新相关。

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

Jon Watte asked 2020-08-06T02:54:15Z
5个解决方案
11 votes

@MSalters

回复“消息队列”:

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

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

您描述的模型是默认行为,它是暂时的,“触发并忘记”行为,并将消息路由到收件人所在的任何地方。 出于这个原因,人们使用RabbitMQ在EC2上进行多播发现。 您可以通过单播TCP pubsub获得UDP类型的行为。 整洁吧?

重新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 / resend管理器,则可能会使您再次慢下来。 这完全取决于您的用例。 如果您真的真的需要使用UDP和懒惰等等,那么您可以剥离RabbitMQ的TCP并可能实现这一目标。

我希望这有助于弄清为什么我建议在乔恩的用例中使用RabbitMQ。

alexis answered 2020-08-06T02:54:58Z
10 votes

实际上,我现在正在构建这样的系统。

我已经对几种MQ进行了相当多的评估,包括RabbitMQ,Qpid和ZeroMQ。 对于这些类型的应用程序,这些延迟和吞吐量中的任何一个都绰绰有余。 但是,不好的是队列创建时间在半百万个队列或更多队列中。 在经过数千个队列后,Qpid尤其会严重退化。 为了避免该问题,通常必须创建自己的路由机制(总队列数较少,并且这些队列中的使用者正在收到他们不感兴趣的消息)。

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

XML(以及XMPP)非常不适合此操作,因为在绑定到I / O之前,您将钉住CPU处理XML的时间很长,这不是您想要的。 目前,我们正在使用Google协议缓冲区,这些缓冲区似乎很适合我们的特殊需求。 我们还将TCP用于客户端连接。 过去,我曾使用过UDP和TCP,并且有其他人指出,UDP确实具有一些优势,但是使用起来却有些困难。

希望当我们更接近发布时,我将能够分享更多细节。

Tim McClarren answered 2020-08-06T02:55:37Z
5 votes

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

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

我们尝试跟踪此处发生的情况:

[http://www.rabbitmq.com/how.html](请确保也单击del.icio.us上的用例列表!)

请看看。 我们在这里为您提供帮助。 请随时通过info@rabbitmq.com给我们发送电子邮件,或在Twitter(@monadic)上打我。

alexis answered 2020-08-06T02:56:15Z
3 votes

FWIW,对于中间结果不重要的情况(例如定位信息),Qpid具有“最后值队列”,该值只能将最新值传递给订户。

Steve Huston answered 2020-08-06T02:56:36Z
2 votes

我的经验是使用非开放式替代品BizTalk。 我们学到的最痛苦的教训是这些复杂的系统并不快。 从硬件需求中可以看出,这直接转化为大量成本。

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

因此,请设计您的体系结构,以便轻松地从COTS队列服务器开始,然后在发现瓶颈时将每个队列(类型)移至自定义队列服务器。

同样,出于类似的原因,请不要假设消息队列体系结构最适合您的应用程序具有的所有通信需求。 以您的“实例中的实体位置”为例。 这是典型的情况,您不希望保证邮件的传递。 之所以需要共享此信息,是因为它一直在变化。 因此,如果丢失了一条消息,则您不想花费时间来恢复它。 您只需发送受影响实体的旧位置。 相反,您想发送该实体的当前位置。 从技术角度讲,这意味着您需要UDP,而不是TCP,并且需要自定义的丢失恢复机制。

MSalters answered 2020-08-06T02:57:11Z
translate from https://stackoverflow.com:/questions/1919472/low-latency-large-scale-message-queuing