在Change.org用Elixir实现社会变革

180 阅读7分钟

欢迎来到我们关于公司在生产中使用Elixir的系列案例研究。请看我们迄今为止发布的所有案例

Change.org是一个社会变革平台,在全球拥有超过4亿用户。两年前,他们的工程团队面临着一个挑战,即把他们的信息传递系统从外部供应商迁移到内部解决方案,以降低成本并获得灵活性。

这篇文章将讨论他们如何处理这个问题,为什么选择Elixir,以及他们的系统如何发展到每月提供超过10亿封邮件。Change.org也在招聘Elixir工程师,加入他们的团队

通往Elixir的道路

Change.org的工程团队的第一步是勾勒出他们系统的要求。该系统将接收数以百万计的事件,如竞选活动的更新、新的请愿书等,并应在适当的时候向所有相关方发送电子邮件。他们正在寻找一个以事件驱动为核心的解决方案,其中并发性和容错性是强有力的要求。

下一个阶段是用不同的编程语言建立概念验证。并非很多公司能够承担这一步骤,但Change.org的团队知道新系统对他们的业务至关重要,并希望在他们的分析中做到彻底。

大约在这个时候,工程总监John Mertens休完育儿假回来了。他利用这个机会尽可能地追赶不同的技术。这时,他偶然发现了José Valim在Lambda Days的演讲,其中讨论了Elixir生态系统中的两个库。GenStageFlow

他们在四种技术中开发了原型。JRuby、Akka Streams、Node.js和Elixir。其目的是评估性能、开发者体验和社区对其特定用例的支持。每种技术都必须尽可能快地处理10万条消息。John负责Elixir的实施,并将他新学到的知识用于实践。

经过两轮评估,该团队选择了Elixir。他们的3名工程师团队有18个月的时间,用他们自己的Elixir实现来取代他们过去几年一直在使用的堆栈。

学习Elixir

当他们开始这个项目时,最初的团队成员中没有一个人有过Elixir的经验。只有Justin Almeida在项目运行6个月时加入,他以前使用过Elixir。

幸运的是,团队感到得到了社区中不同资源的支持。约翰回忆说。"我们在早期的一次会议上讨论如何将Elixir引入我们的堆栈,这时Pragmatic Programmers公布了Adopting Elixir一书,这本书对回答我们的许多问题非常有帮助。"

新系统

该团队开发了三个Elixir应用程序来取代外部供应商。第一个应用程序处理所有传入的事件,以决定是否应该发送电子邮件以及发送给谁。

下一个应用程序是有效负责发送电子邮件的应用程序。对于每封邮件,它都会找到合适的模板以及用户的地域和偏好。然后,它组装电子邮件,并在邮件传输代理(MTA)的帮助下将其发送。

最后一个应用程序是负责分析的。它接收来自MTA的webhook调用,并对不同的事件进行分批处理,并将其输送到他们的数据仓库供以后使用。

大约四个月后,他们将新系统投入生产。虽然Change.org有几十种不同的电子邮件模板,但最初的部署处理了一个单一的、直接的案例:密码恢复。

一旦新系统投入生产,他们继续将不同的用例迁移到系统中,日复一日地增加处理的事件和发送的邮件数量。一年后,他们提前完成了迁移工作。

处理尖峰和负载调节

今天,这些应用在相对较少的节点上运行。前两个应用使用6到8个节点,而最后一个应用只使用两个节点。

约翰解释说他们是超额配置的,因为系统中的尖峰是相对频繁的。"对于大型活动,一个事件可能会扇动到数千或数十万封电子邮件"。

该团队非常友好地分享了他们的一些内部图表。在下面的例子中,你可以看到一个超过1000万封邮件进入系统的峰值。

image.png

一旦发生这种突发事件,所有节点的CPU都会达到最大值,每秒发出约3000封邮件,直到耗尽消息队列。整个过程中,内存使用率保持在5%。

GenStage库提供的背压对系统的性能起到了关键作用。 由于这些应用程序从消息队列中获取事件,处理它们,并将它们提交给第三方服务,它们必须避免堆栈的任何部分过载。GenStage通过允许不同的组件(在库的术语中称为阶段)交流它们现在能处理多少数据来解决这个问题。例如,如果向MTA发送消息的速度比平时慢,系统自然会从队列中获得更少的事件。

该系统的另一个基本特征是分批工作。如果能分批而不是逐一地接收和发送数据,会更有效率和成本效益。约翰在ElixirConf欧洲会议上做了一个演讲,分享了他们从第一万亿条信息中获得的经验

去年,Change.org上的活动也有了很大的增长。这些系统应付得很好。贾斯汀说:"一切都运行得很好,以至于有些服务并不在我们的考虑范围之内。"

与生态系统合作

Change.org在可能的情况下依靠并促进了生态系统。在迁移过程中,新旧系统都必须访问许多共享资源,如HAML模板、Ruby的I18N配置文件和Sidekiq的后台队列。幸运的是,他们能够在Elixir生态系统中找到兼容的库,分别是calliopelinguistexq

如今,这些库中的一些已经失去了味道。例如,社区选择了gettext进行国际化,因为它是一种更广泛接受的格式。出于这个原因,Change.org已经介入并接管了linguist库的所有权。

随着Change.org采用Elixir,生态系统也在增长,以更好地支持他们的用例。最近的一个例子是Broadway库,它使数据管道的组装变得容易。约翰解释说。"Broadway建立在GenStage之上,所以它提供了我们需要的负载调节、并发性和容错性。它还提供了批处理和分区,这些都是我们最初必须自己建立的。对于新项目来说,Broadway是我们进行数据摄取和数据处理的首选。"

Elixir作为默认堆栈

随着项目迁移到Elixir,Elixir已经非正式地成为Change.org后端服务的默认堆栈。今天,他们有20多个项目。工程团队也在他们的事件驱动架构中汇聚了一个共同的服务模式,用Broadway和Phoenix构建。

简而言之,他们使用Broadway来摄取、聚集和存储数据库中的事件。然后,他们使用Phoenix来公开这些数据,或者通过API,作为分析,或者作为内部团队的工具。

最近的一个例子是Change.org的Bandit服务。该服务提供了一个Phoenix API,决定在其产品的各个部分向用户展示哪个副本。当用户与这些副本互动时,数据被送入系统,并与Broadway分批进行分析。他们利用这些反馈来优化并在未来做出更好的选择。

由于他们在内部组织的多种培训和实践社区,该团队也已发展到10名Elixir开发人员。Change.org也在寻找Elixir后端工程师,因为他们旨在为他们的团队带来经验和多样性。有兴趣的开发者可以在他们的网站上了解更多关于这些机会