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

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

内容简介:[译]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 如何处理每分钟超过一百万次的突发请求


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

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

Tagging

Tagging

Gene Smith / New Riders / 2007-12-27 / GBP 28.99

Tagging is fast becoming one of the primary ways people organize and manage digital information. Tagging complements traditional organizational tools like folders and search on users desktops as well ......一起来看看 《Tagging》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具