SendGrid如何缩放到40亿封电子邮件每月

8,851
11
Twilio SendGrid
Twilio SendGrid是数字通信平台,使企业与客户通过电子邮件可靠有效和大规模搞。

撰稿赛斯亚扪人在SendGrid首席工程师


一些背景知识

成立于2009年,从TechStars的程序毕业后,SendGrid开发了一种颠覆行业的基于云的电子邮件服务,以解决为成长型公司可靠发送电子邮件的挑战。我们现在每天发送超过10亿封电子邮件(最多一天发送超过20亿封邮件)给像这样的公司SpotifyYelp尤伯杯,制作的Airbnb。我们专注于工作,使我们的客户取得成功,达到他们的客户。如果你打开你的收件箱,有机会,一些邮件是通过SendGrid发送。

在这里我是首席工程师,我已经在过去的七年我们的后端基础设施的几乎所有方面的工作。目前,我负责我们站MTA队(邮件传输代理,软件与邮箱提供商通信)工作。该小组是根据我们的欧文办公室,我真的很喜欢来,每天上下班。我们拥有一支专注于可测试的,高质量的软件,以及我们专注于工程卓越的驾驶是我们的经理,谁是以前为我们传递和处理团队开发者和团队领导能力的辅助。

除了我们的重点是确保发送和从收件箱中供应商的多种处理响应,我们的工作包括退回的电子邮件和取消订阅的处理。我们密切合作,经常配对的更为艰巨的任务,努力确保做出想要的邮件传递和维护灭火系统,以防止不必要的邮件被处理。


在SendGrid工作的早期

从一开始,SendGrid的后端架构就发生了很大变化。它最初是一个经过美化的Postfix安装,后来发展成了一个大型的基于推的系统,而这个系统目前正在转变为一个更可扩展的基于拉的模型。作为转型的一部分,我们正在将越来越多的服务转移到云端。

在我们传统的基于推的系统中,SMTP或HTTP API请求通过我们的边缘节点进入,这些节点将请求推入我们处理集群的磁盘上队列。在此之后,邮件会根据用户的设置进行更改(链接跟踪、取消订阅页脚、动态内容替换等),然后推送到MTA软件的磁盘队列中。在将邮件放入MTA的队列后,MTA将尽可能快速有效地将邮件发送出去,同时应用算法提高邮件的可交付率。

该系统的工作非常出色,但它也有一些缺点,如潜在事件发生时的处理延迟或全部节点发生故障时甚至潜在的邮件丢失。在这些缺点的光,我们已经朝着通过分布式文件系统支持的基于拉的模式工作。


我们目前的架构

在我们新的基于拉的模型中,基本的系统仍然存在(边缘节点接收、处理、交付);但是,我们已经将动态操作从推入队列转换为从定制的分布式队列中拉出(稍后将详细介绍这一点)。这一变化使我们的系统成为临时的、无状态的服务,可以以更实时的方式向上或向下旋转以满足客户的需求,随着我们加入和使用Amazon Web services (AWS),这一点将更加明显。

大多数我们的后端服务书面(或改写)在。我们的系统的并发性使走自然和容易的选择,因为我们从Perl的AnyEvent和Python的感动扭曲的。这些服务利用Redis的和/或Redis的哨兵缓存和MySQL的数据持久性。度量发射到石墨并显示在Grafana。日志从STDOUT发送到系统日志,在那里我们有啜这些日志了公用事业卡夫卡Splunk的。我们已经完成了警报设置PagerDuty并且将其送至开来的Splunk警报和数据美国标准检查。

还记得当我提到一个自定义的,分布式队列?对于服务之间的排队,我们的球队之一,开发了由Ceph的支持服务,即SGS(SendGrid调度器)一个专门的“堆的堆”。需要这项技术的核心部分,以确保我们可以在不排挤小发件人或不太流行的收件人域相当出队的消息时,大用户发送大爆炸流行的收件箱中的域。

把这个收回来,我们的大都会运输署的技术堆栈是什么样的?以前的遗留版本是Perl的AnyEvent,它有一个父进程,父进程派生出子进程。父母安排工作,孩子们投递邮件。切换到Go删除了调用地狱和分支,因为Go的并发模型比任何事件都更容易处理。静态类型和编译让我们实际上知道在任何给定函数中有哪些变量,缺少这些变量是Perl服务的一个主要缺点。所以,是的,我们喜欢去。

请进入MTA的,我们争取用或者客户的IP地址,或共享一个从我们的泳池收件箱提供商的连接。一旦我们建立一个连接,我们吼出尽可能多的邮件用户该电子邮件域收件箱提供商将允许。我们冲洗和重复,以确保每一个客户和各个领域得到邮件投递一个公平的机会。


测试服务电子邮件

我们的一个最近和有趣的挑战是我们如何确保系统保真度,我们感动,继续移动,从一个Perl集中堆去。基本上有你如何能做到这一点两个思想流派:测试所有的东西或快速部署,快速将恢复生产。我们已经做了很多的都有。我们已经投入了一点努力在提高我们的工具和周围监测快速部署和快速恢复。事实上,就在昨天,我们的新队员,我部署一个新的缓存策略,它只是提上了一个生产节点有人回复之前1分钟左右(在我们的预生产环境中工作的巨大后)。

有一些事情是几乎不可能试生产之前,在这种情况下,这是iptables的。生产特定的设置之外,我们有一个系统,客户期望的东西,只是工作™。在我们的规模,我们的团队,使用生产作为测试可能会导致丢失的邮件。与此同时,我们需要重构和/或重写代码,以跟上我们的成长。为了能够有信心做到这一点,它需要测试,测试,和更多的测试。

我们有我们的单元测试套件,单元集成化测试(测试,验证我们直接与数据库的集成,缓存,和一阶连接服务),和系统集成测试,使用我们的电子邮件发送API发送一封电子邮件通过我们的整个系统,确保预期事件被发送到用户的人,收到消息收件箱预期的数据。


Dockerizing SendGrid

对于单元集成层,我们利用了它搬运工人。我们进入的边缘是当上游服务完成处理消息并把它给我们发货,然后我们外出边缘实际上是与某人的收件箱通信。我们实际上并不希望建立一堆接收MTA和这样的,但我们仍然需要测试的行为在该层。我们的解决方案仍处于进展中的工作,但它得到的覆盖,我们可以自信地重构,推动新的功能和知道,我们没有破坏任何东西使用情况的大部分份额。

这个Docker设置利用DNSMasq来设置MX和A记录,并确保它们指向正在运行的模拟收件箱接收。这些收件箱是从一个有多个选项的基本映像配置的。我们可以指定接收的TLS证书过期或设置不当,我们可以让它们在不同的SMTP对话部分缓慢响应或出现给定的错误。我们可以确保我们后退和延迟电子邮件,如果收件箱提供商说这样做。这种对外部世界的详细伪装使我们能够自动化各种外部行为,并确保我们的服务按预期运行。

除了看中泊坞窗的设置,我们已抓获和消毒生产日志为我们遗留的Perl MTA的行为,我们可以测试从新转到版本输出日志的行为与旧版本相同。这些测试都设置为允许我们和MTA的传统和新版本之间切换,确保这两个系统在传统兼容的方式运行。我们不仅可以确保我们对各种各样的,我们已经看到了从收件箱时操作的问题,但我们知道,我们的MTA的最新版本继续覆盖所有的旧版本相同的预期行为。

这些测试还是很快的在我们的CI系统中,运行我们所有的单元集成测试,并在五分钟内生成工件并准备部署。如果不是抓取Docker图像,我们的本地开发环境可以在10秒内运行这些单元集成测试。

我们在码头工人在当地发展,因为我们刚刚进入。我们的docker-compose文件旋转了花哨的DNS设置,我们所有的依赖容器,使我们能够针对各种MX和TLS设置测试MTA,还有多种潜在的收件箱中的反应和行为。每个人都使用自己选择的编辑,我们经常配对更复杂的任务,以防止孤立的系统认识。

当我们通过代码审查(每一个代码和配置的变化经过代码审查)和关于自动化测试水平手感好了(没有人可以在他们自己的代码的功能搁笔;质量保证工程师或其他开发人员必须验证功能),我们通过BOT合并我们的变化是与交互GitHub上(机器人保持我们的版本和更改日志)。后BuildKite有一个绿色的构建和我们的二进制运到我们的回购服务器,我们是很好的推出将部署到我们的数据中心,并不断推动我们的系统的性能针。


在闭幕

我们的系统在改变,我们的能力在增加,我们的问题仍然很有趣。每到周一,我都很兴奋地挽起袖子,帮助推动我们的产品不断扩大规模。能成为这家不断创新、不断改进、每天为客户提供更好服务的公司的一员,我感到非常荣幸。

SendGrid一直在寻找顶尖人才加入我们的团队。有关SendGrid职位的更多信息,请访问我们的职业页面:https://sendgrid.com/careers/

Twilio SendGrid
Twilio SendGrid是数字通信平台,使企业与客户通过电子邮件可靠有效和大规模搞。
经核实
首席软件开发
你也可能喜欢
一条线的改变如何减少99%的克隆时间
该开发者指南SSO
特性标志:平滑部署的3个用例
通过轻量级的排名提高推荐的pin的质量