[译]Discord 如何处理每分钟超过一百万次的突发请求

栏目: Erlang · 发布时间: 6年前

内容简介:[译]Discord 如何处理每分钟超过一百万次的突发请求

原文: how discord handles push request bursts of over a million per minute with elixirs genstage

译者:杰微刊兼职翻译巫明瀚

Discord团队观察到了他们的业务有巨大的增长。为了应对这种增长,我们的工程师团队开始开心的调研应该如何去扩展后端服务。

我们在Elixir's GenStage这项技术上看到了巨大的成功。

一场完美的风暴:守望先锋和Pokémon GO

今年夏天,我们的移动推送通知系统展开了了一场战斗。 / r /(注①) Overwatch的Discord刚刚超过25,000并发用户,Pokémon GO 的Discords也在这个数字左右,突发信息成为一个真正的问题。

突发信息使整个推送通知系统变得异常缓慢,并且有时还会发生停止。用户可能延迟收到或者根本收不到推送信息。

我们意识到我们可以通过XMPP而不是HTTP向Firebase发送推送请求,立即提高吞吐量。

Firebase XMPP比起HTTP要麻烦一些。 因为Firebase要求每个XMPP连接每次只能有不超过100个的待处理请求。如果你有100个请求在处理途中,那么必须等Firebase确认完该次请求之后才会发送下一个请求。

由于一次只能处理100个请求,因此我们需要设计我们的新系统,使XMPP连接在突发情况下不会超载。

从最初的考虑来看,GenStage对于我们的问题来说似乎是最佳的解决方案。

注①:reddit的/r/板块 ## GenStage的救援 经过一番调查,我们确定了将推送通知发送到Google Firebase Cloud Messaging服务的主要瓶颈。

GenStage

那么, GenStage是什么? 

GenStage是一种新的Elixir行为,用来在Elixir进程之间交换事件与压力负载。

这意味这什么?基本上,它能给予你必要的工具,来确保你的系统的每一部分都获取到负载。

在实践中,具有GenStage行为的系统通常具有几个阶段(stage)。

阶段(stage)是接收并且(或者)发送来自其他阶段的数据的计算步骤。

当一个阶段发送数据时,它是生产者,当一个阶段接收数据时,它又是消费者.某个阶段可能集生产者和消费者的角色于一身。

除了生产者或消费者的角色外,如果一个阶段只生产项目,那么它被称为"源(source)",如果一个阶段只消耗项目,那么它被称为"接收器(sink)"。

工作方法

[译]Discord 如何处理每分钟超过一百万次的突发请求

一个重要的图表 

我们将系统分为了两个GenStage阶段,一个"源"和一个"接收器"

* 阶段 1 -推送收集器(Push Collector):推送收集器是收集推式请求的生产者。每台机器目前有一个推送收集器Erlang(注①)进程。

* 阶段 2 -推送器(Pusher):推送器是一个消费者,它需要来自推送收集器的推送请求,并将请求推送到Firebase,它一次只需要100个请求,以确保它不超过Firebase的待处理请求限制。每台机器有很多的推送器Erlang进程。

注①:Erlang是一种通用的并行 程序设计语言 ,它由 乔?阿姆斯特朗 (Joe Armstrong)在 瑞典 电信设备制造商 爱立信 所辖的计算机科学研究室开发。

使用GenStage进行压力负载和负载脱落 

GenStage有两个关键的特性能在请求突发期间给予我们帮助:压力负载和负载脱落。

压力负载

在推送器中,我们使用GenStage的需求功能来向推送收集器发起询问,以获得推送器能处理的最大请求数量。这能确保推送器待处理请求的数量上限.当Firebase确认了这些请求后,推送器便能从推送收集器继续获得更多的请求。

推送器知道Firebase XMPP连接可以处理的请求的确切数量,并且不向推送收集器要求更多的请求。而除非推送器要求,否则推送收集器不会主动向推送器发送请求。

负载脱落

由于推送器对推送收集器施加了压力负载,因此在推送收集器处,我们会有一个潜在的隐患。特别巨大的推送突发状况可能会使推送收集器过载。

GenStage有另一个内置功能来处理这个:缓冲事件。

在推送收集器中,我们指定要缓冲的推送请求数。通常缓冲区是空的,但是在大约每月发生一次的灾难性情况下,它会派上用场。

如果系统中有太多的信息在移动,并且缓冲区被填满,则推送收集器可能将会释放传入的推送请求。这可以通过简单地在推送收集器的init函数中指定buffer_size选项来使用GenStage,而且没有额外的开销。

有了这两个功能,我们便能够处理突发通知的情况.

代码(重要部分)

下面是我们如何设置我们的阶段(stage)的示例代码。为了简单起见,我们删除了很多错误处理的代码,例如当连接断开时或者Firebase返回错误等。

如果只想查看系统的结果,可以跳过代码。

推送收集器(生产者)

[译]Discord 如何处理每分钟超过一百万次的突发请求

推送器(消费者)

[译]Discord 如何处理每分钟超过一百万次的突发请求

一个示例事件

下面是新系统所处理的一个真实的突发事件。上图是每秒流过系统的推送请求数。下图是由推送收集器缓冲的推送请求的数量。

注意:这些图表来自我们部署新系统后的第一个事件。自那以后,我们每秒的推送

[译]Discord 如何处理每分钟超过一百万次的突发请求

[译]Discord 如何处理每分钟超过一百万次的突发请求

量增加了一倍以上。此外,我们只在用户的应用不处于活动状态时发送推送。

事件发生顺序:

~17:47:00—系统一切正常.

~17:47:30—我们开始接收一串消息。推收收集器的缓冲器计数随着推送器的响应而减小。不久后,缓冲区下降了一点。

~17:48:50—推送器中信息的涌入速度要大于信息的处理速度,因此推送收集器中的缓冲区开始填充。

~17:50:00—推送器收集器缓冲器开始进入峰值并释放一些请求。

~17:50:50—推送收集器峰值停止。

~17:51:30—请求峰值开始下降.

~17:52:30—系统完全恢复正常.

在整个事件期间,对系统或用户都没有产造成明显的影响。显然这次事件中有几个通知被推送收集器释放掉了,但是如果这几个通知没有被释放,系统可能永远无法恢复,或者推送收集器可能已经崩溃。我们认为某些事情的损失是完全可以接收的折衷方案,比如这些通知。

Elixir的成功

在Discord上,我们非常高兴的使用了Elixir / Erlang作为我们的后端服务的核心技术。我们也非常兴奋能看到在Erlang/OTP的坚实的技术基础上增加了类似GenStage这样的新功能。

我们正在寻找一些具有进取精神的人来解决一些在Discird的快速增长遇到的问题。

如果你喜欢游戏并且对这些问题感到有兴趣,欢迎加入我们。

欢迎移步解放号论坛,更多精彩活动等您参加~

------------好久不见的分隔线------------


杰微刊旨在分享优质的内容。
我们水平有限,但理想高远。
也同样期待有理想的您对这个世界的贡献。
欢迎任何目的的联系。

欢迎关注我们

[译]Discord 如何处理每分钟超过一百万次的突发请求


以上所述就是小编给大家介绍的《[译]Discord 如何处理每分钟超过一百万次的突发请求》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Defensive Design for the Web

Defensive Design for the Web

37signals、Matthew Linderman、Jason Fried / New Riders / 2004-3-2 / GBP 18.99

Let's admit it: Things will go wrong online. No matter how carefully you design a site, no matter how much testing you do, customers still encounter problems. So how do you handle these inevitable bre......一起来看看 《Defensive Design for the Web》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具