11 月 19 - 20 日 Apache Pulsar 社区年度盛会来啦,立即报名! 了解详情
写点什么

2020 年美国大选技术平台架构

  • 2021-11-03
  • 本文字数:7610 字

    阅读完需:约 25 分钟

2020年美国大选技术平台架构

在 2020 年美国总统大选中,我担任拜登阵营的首席技术官。在 2020 年 11 月的 QCon Plus 大会上,我做了一个演讲,分享了我们的团队为竞选而做的架构以及为了解决各种问题而开发的特殊工具。这篇文章是这次演讲的提炼总结。


作为首席技术官,我领导着竞选阵营的技术团队。我负责整体的技术运营工作,与我的优秀团队一起构建出了总统竞选活动中最好的技术栈。


我们涉足了所有东西,从软件工程到 IT 运营,再到网络安全,以及它们之间的方方面面。


我作为 Target 的一名工程师加入竞选阵营,专注于基础设施和运营,构建高可伸缩且可靠的分布式系统。在 2016 年希拉里竞选美国总统期间,我作为 Groundwork 的员工参与了竞选技术平台的工作。Groundwork 是一家专门为竞选活动提供技术支持的公司。

竞选活动组织结构

错综复杂的竞选组织结构对技术选型的方方面面都有很大的影响。


图 1 列出了竞选组织的各个部门,让你对各个部门的职责有一个大致的感受。



图 1:竞选活动的组织结构


每一个团队都有自己关注的方面。尽管技术受到媒体的关注,但从政治角度来看,它并不是最重要的。我们的目标是接触选民,让他们发声,让尽可能多的人加入民主进程。

技术在竞选活动中的位置

在竞选活动中,技术需要完成任何需要它完成的事情。竞选活动的几乎每一个方面都需要一种技术形态。我的团队需要负责构建和管理我们的云平台、所有的 IT 运营工作、供应商入驻,等等。


简单地说,我们构建技术的方式就是通过“胶水”将供应商和各种系统“粘合”在一起。我们所处的环境让我们不能像开发成熟产品那样做。


如果我们需要某种工具,但没有相应的供应商可以提供或者找不到开源的,也没有足够的预算,我们就自己开发。


竞选活动技术要做的大部分事情是将数据从 A 点移动到 B 点。严格来说,就是创建了很多 S3 桶。


另外,我们在过去几年开发了很多东西。我们构建了数十个网站,有大型的,也有小型的。我们为外勤团队开发了一个移动应用。我们为竞选团队成员开发 Chrome 插件,帮助他们减轻工作负担。我们还开发了 Word 和 Excel 宏来提高工作效率,尽管这些事情很枯燥无味。在总统竞选活动中,时间就是一切,我们所做的每一件可以节省时间的事情,哪怕只节省了一分钟,也是值得我们投入的。


我们所做的大部分工作是通过自动化任务减轻竞选团队的工作负载。竞选活动技术的精华部分可以提炼成:数据、数字化、IT 或网络安全。实际情况是,竞选活动的技术都是关于这些东西,它是竞选活动重要的组成部分。

我们做了哪些事情

我们的团队不大,但我们生气勃勃,都是充满斗志的技术狂人。我们接下所有的需求,并尽力做到最好。在竞选活动期间,我们构建并交付了超过 100 个服务。我们构建了超过 50 个 Lambda Function,提供各种各样的功能。我们还为初选开发了一个叫作“Team Joe”的关系结构组织移动应用,可以把数千名热切的选民和志愿者跟他们认识的人联系起来。


我们进行了超过 10000 次部署,零停机,并保证了稳定性和可靠性。


我们基于云机器学习实现了自有搜索平台,具备健壮的自动化能力,为活动节省了数万小时的人工工作量,并为我们带来非常有深度的见解。我们基于强大的机器学习基础设施构建了很多服务。


竞选活动一开始就承若,我们将以高标准来要求自己,并确保不接受来自伤害地球的组织或别有用心的个人的捐赠。为了信守承诺,我们建立了一个自动化框架,几乎可以实时地审查我们的捐助者是否遵守联邦选举委员会的规定和竞选承诺。


我们赢得了初选,并希望在大选的网站上打造一个新的品牌。所以我们为 joebiden.com 带来了一种全新的体验。


竞选活动的一个重要方面是直接接触选民,让他们知道他们所在地区发生了什么,或者是什么时候可以投票。为此,我们建立了一个全国范围内的短信推广平台。在这一过程中,我们节省了数百万美元的运营费用。除此之外,竞选总部和州总部也开始 IT 化运作,最终在疫情隔离开始时成为一个可以完全远程运作的组织。


我们通过这些确保了我们拥有世界级的网络安全,这是我们所做一切的核心。


但不管怎样,竞选活动中的任何一项工作都不只是个体的责任,每个人都需要在任何时候、任何地点提供帮助,无论是打电话让选民去投票、发送短信还是收集签名让他们参加投票。这些我们都做了。

基础设施和平台

我们所做的一切都依赖于云基础设施。最重要的是,我们没有花太多宝贵的时间在重新创造轮子上。我们使用 Pantheon 来托管主网站 joebiden.com。对于非网站的工作负载、API 和服务,我们把它们部署在 AWS 上。此外,我们在 AWS 部署了一个小型 Kubernetes,帮助我们更快地交付简单的工作负载(主要用于 CRON 作业)。


我们仍然需要快速交付大规模服务。作为一个小团队,我们的构建和部署管道的可重复性就变得非常重要。对于持续集成,我们使用了 Travis CI。对于持续交付,我们使用了 Spinnaker。


服务在云端部署并开始运行了之后,它们都需要一组核心功能,比如如何找到其他服务并安全地访问配置和秘钥。为此,我们使用了 HashiCorp 的 Consul 和 Vault,这帮助我们构建了完全不可变和差异化的开发环境和生产环境,很少需要手动操作服务器——不是完全不需要,但真的非常少。


很大一部分技术工作是由分析团队完成的。为了确保他们能够获得最好的工具和服务,我们将分析数据保存在 AWS Redshift 中。它提供了一个高度可伸缩的环境,可以对资源利用做到细粒度控制。


我们将 PostgreSQL 作为服务的后端数据存储。


从运维的角度来看,我们希望应用程序的日志记录活动有一个中心视图,以便我们能够快速地排除和诊断问题,实现最快的故障恢复。为此,我们部署了一个 ELK 栈,并使用 AWS Elasticsearch 来存储日志。日志对于应用程序来说非常重要。指标提供了服务运行状态的洞见,在与我们的轮岗待命机制集成时,它们是非常关键的信息来源。在服务水平指标方面,我们部署了 Influx 和 Grafana,并将它们连接到 PagerDuty,确保不会遇到未知的中断。很多自动化工作负载和任务并不适合使用传统的部署模型,对于这些,我们会尽可能使用 AWS Lambda。我们还将 Lambda 用于需要与 AWS 生态系统其他部分集成的工作负载,以及基于数据呈现的扇出作业。


我们构建了一个真正的多语言环境。我们用各种语言和框架构建了服务和自动化机制,我们能够以无与伦比的弹性和速度做到这些。


我们在竞选期间涉及了很多领域。要把我们所做的每一件事都彻底细化需要花费一生的时间,所以我将挑选一些有趣的架构,这些架构是由负责软件工程的技术团队做起来的。当我深入讨论架构时,请注意,对于我所讨论的每个细节,至少还可以做十几次分享,它们涵盖了我们整个技术团队所完成的工作的广度。

捐款者审核

正如前面提到的,竞选活动一开始就承诺拒绝某些组织和个人的捐款。要大规模做到这一点,唯一的办法是让一群人定期梳理捐款,通常是每季度梳理一次,并标出可能匹配筛选条件的捐款者。


这个过程很困难,很耗时,而且容易出错。如果是手工操作,通常需要为个人捐赠的金额设定一个门槛,然后研究捐赠者是否符合我们标记的有问题的类别。


为了提高效率,我们构建了一个高度可伸缩的自动化流程,将捐赠的细节与我们想标记的一组标准相关联。我们每天都会启动一次流程。它将 NGP VAN(这是所有捐款信息的真实数据来源)中的捐款数据导出到 CSV 文件,并转储到 S3 中。将 CSV 文件存储到 S3 将会触发一个 SNS 通知,该通知反过来将激活一系列 Lambda Function。这些 Lambda Function 将文件分割成更小的块,将它们重新导入到 S3,并启动捐款者审查流程。在这个工作流执行时,我们可以看到有大规模的 Lambda,多达 1000 个并行执行的捐款者审查代码。


例如,我们承诺不接受来自天然气和石油行业的说客和高管的捐款。这个过程只需要几分钟,就可以完成对捐赠者的全面审查,并将其与说客、外国代理以及油气公司高管的黑名单进行核对。


在这个流程完成之后,标记的条目将被整理成单个 CSV 文件,然后将该文件重新导到 S3,供下载使用。随后,SES 将向开发人员 Danielle 发送一封电子邮件,表明标志已准备好,可以进行进一步的验证。验证之后,结果被转发给合规团队,他们将采取适当的行动,可能是进行退款或做进一步的调查。



图 2:自动化捐款者审核流程


如果只是说这个过程为竞选节省了大量的时间,那也太轻描淡写了。捐款者审查管道很快成为技术平台的核心组件和竞选活动的重要组成部分。

Tattletale

在一开始,我们的团队规模还很小,但我们有很多供应商和云服务,没有足够的时间和人手来检查这些服务的安全状态。我们需要一种简单的方法来制定规则,针对关键的面向用户的系统,确保我们总是遵循网络安全最佳实践。


Tattletale 正是为此而开发的一个框架。Tattletale 是我们在竞选活动中构建的最重要的技术之一。


我们设定了一组任务,利用供应商系统 API 来确保开启了双因子身份验证之类的功能,或者如果用户帐户在系统中是活跃的,但该用户有一段时间没有登录,我们就会收到通知。休眠帐户存在安全风险,因此我们希望确保所有配置都是面向最低权限的。


此外,Tattletale 中的规则可以检查负载均衡器是否无意中暴露在互联网上、IAM 权限的范围是否太广,等等。在审计规则集之后,如果 Tattletale 发现了违规行为,它会通过 Slack 频道发送通知,让相关人员进行进一步的调查。它还可以通过电子邮件通知用户有违规行为发生,这样用户就可以自行采取纠正措施。如果超出了某个阈值,Tattletale 会在 Grafana 中记录一个指标,触发 PagerDuty 升级策略,并立即通知待命的技术人员。



图 3:Tattletale 架构


当我们没有时间或资源查看安全问题时,Tattletale 就成了我们的网络安全之眼。它还确保了我们遵循一套公共的网络安全标准,并尽可能保持最高标准。

Conductor 和 Turbotots

当我们的内部工具达到一定的复杂性和广度时,我们需要更好地管理这些 API。为了管理那些系统,我们需要合并我们所构建的 UI。我们还需要标准化安全模型,这样就不会到处都是自定义身份认证和授权。


因此,我们创建了 Conductor(因为拜登喜欢火车,就用售票员来命名)、我们的内部工具 UI,以及 Turbotots(我们根据土豆来命名的众多工具之一),也就是我们的平台 API。



图 4:Conductor 和 Turbotots


图 4 实际上是对一个复杂架构的简化图,但这些概略的描述足以让你了解 Conductor 和 Turbotots 做了哪些事情。


Conductor 成为我们为竞选工作人员开发的所有内部工具的统一入口。换句话说,这是所有参与竞选活动的人想要访问我们提供的服务都必须经过的地方。Conductor 是一个 React Web 应用,通过 S3 来部署,并通过 CloudFront 来分发。


Turbotots 是一个统一的 API,它为我们所做的一切提供了通用的身份认证和授权模型,与 Conductor 通信也是通过它。我们在 AWS Cognito 上构建了 Turbotots 的 AuthN 和 AuthZ 部分,这节省了大量工作,并通过 G Suite/Google Workspace 提供了简单的单点登录(SSO)功能。身份验证是通过解析 JWT 令牌来实现的。为了在前端管理好它们,我们使用了 AWS Amplify 的 React 绑定,它被无缝地集成到应用程序中。


图 4 右侧的内容有点难以理解,我会尽量简化。正向 API 是一种 API 网关,包含了完整的代理资源。API 网关可以很容易与 Cognito 集成,这帮助我们实现了 API 请求的安全性。与 API 网关集成的 Cognito 授权器也会在请求通过代理之前执行 JWT 验证。我们可以通过它清楚地知道请求在发送到后端之前已经过完整的验证了。


在开发 API 网关代理资源时,你可以通过 VPC 网络负载均衡器让运行在 VPC 中的代码连通起来。这很复杂,但据我所知,它有效地在 AWS 内部的 API 网关和你的私有 VPC 之间创建了一个弹性网络接口。反过来,NLB 被附加到一个包含一组 NGINX 实例的自动伸缩组中,作为我们的统一 API。这就是 Turbotots 的主要部分,本质上就是在 VPC 中运行的所有内部服务的反向代理。在这种模式下,我们不需要向公网公开任何 VPC 资源。我们可以依赖 AWS 内置的安全装置,这让我们大家都轻松多了。


当请求到达 Turbotots 时, Turbotots 中的轻量级 Lua 脚本就会提取 JWT 令牌的用户信息部分,并将该数据作为新的请求负载的一部分传递给下游服务。当请求到达目标服务时,它就可以检查用户信息,看看是否对该用户的请求做了验证。


用户可以被添加到 Cognito 的授权组中,这样他们就可以在下游服务中获得不同级别的访问权限。最小权限原则在这里仍然适用,并且没有默认权限。


Conductor 和 Turbotots 作为一个统一的用户界面,为内部工具提供了与 G Suite 帐户的无缝 SSO 集成。在下一节,我们将介绍如何使用相同的架构向非内部用户公开部分 API。

Pencil 和 Turbotots

Pencil 是一个点对点短信平台,从一系列简单的早期需求开始,发展成为一个我们为之投入了大量时间的庞大架构。


自己构建 P2P 短信平台的初衷是为了节省成本。我知道,我们可以通过 Twilio 发送短信,这比任其他何一个供应商的收费都要低。但是,在一开始,我们并不需要供应商提供的大量功能,我们很容易就能构建一个简单的短信系统来满足当时的需求。


随着项目越来越流行,它的规模在急剧扩张。Pencil 被成千上万的志愿者用来接触数以百万计的选民,并成为我们选民外联工作流程中的一个重要组成部分。你收到的来自竞选志愿者的短信很可能是通过 Pencil 发送的。


Pencil 的外部架构看起来有点眼熟,我们重用了 Conductor 架构,只做了一些配置修改,不需要修改代码。



图 5:Pencil 的架构看起来很像 Conductor


Pencil 的用户组件是一个通过 S3 部署并通过 CloudFront 分发的 React Web 应用程序。React 应用程序反过来与连接到 Cognito 授权器的 API 网关资源对话。


用户通过电子邮件被邀请到 Pencil 平台,这个在 Cognito 注册账户的过程是独立的。在用户第一次登录时,Pencil 会自动将他们添加到 Cognito 的用户组中,这样他们就可以访问 Pencil 的用户 API。


从用户的角度来看,是他们点击了一个注册链接触发了短信发送。经过竞选活动数字团队的简单操作之后,用户(志愿者)就可以开始工作了。


这是非常容易做到的,因为它是建立在先前的 Turbotots 基础设施之上。

Tots

Tots 的架构与 Turbotots 不同,它位于 Turbotots 的下游。在之前的图中,Tots 解析了 Turbotots 下面列出的很多服务,这些服务是 Tots 架构的一部分。



图 6:Tots 平台


Tots 是一个重要的平台。随着我们构建了越来越多的机器学习工具,我们很快意识到,我们需要合并逻辑和简化架构。


在各种项目中,机器学习最主要的应用场景是从文本块中提取词袋。我们将这些数据保存到 Elastic 的索引中,让数据主题可用于快速检索。我们使用 AWS Comprehend 从文本中提取词袋。这是一个很棒的服务——给它一段文本,它就会告诉你在这段文本中出现的人、地点、主题等等。文本以多种形式进入平台,包括多媒体、新闻文章和文档格式。


图 6Tots 平台中的很多机制都涉及在将内容发送给 Comprehend 之前需要如何处理。这个平台上的流程为竞选活动节省了成千上万个小时的人力工作,包括花时间转录现场活动内容(如辩论),并将它们转换成文本格式,以便竞选人员日后阅读。

CouchPotato

CouchPotato 帮助我们解决了计算机科学中最难的问题:在 Linux 上制作音频。CouchPotato 对我们来说非常重要,因为它为我们制作音频和视频材料节省了大量时间。这也是我们所构建的最强大的技术平台之一。



图 7:竞选活动用 CouchPotato 处理多媒体任务


CouchPotato 是图 7 所示的架构的主要角色,但从连接多个独立服务的连线可以看出,在整个过程中,它也需要其他的支持角色。


CouchPotato 的主要功能是将 URL 或媒体文件作为输入,在隔离的 X11 Virtual Frame Buffer 中打开媒体文件,在 PulseAudio 播放设备(FFmpeg)上收听回放,然后记录 X11 会话的内容。这就产生了一个 MP3 文件,然后将它发送到 AWS Transcribe 进行自动语音识别(ASR)。


在 ASR 完成之后,它会过一遍生成的文本,纠正一些常见错误。例如,它很少能把市长 Pete Buttigieg 的名字写对。我们用 RegEx 做一些常见的文本替换。


在完成这些工作之后,转录文本将被发送到 Comprehend,它将提取其中的词袋。最后,文本被索引到 Elasticsearch 中。


CouchPotato 的关键之处在于它能够利用 FFmpeg 的分段功能生成更小的音频块。它会为每个片段执行整个过程,并确保被索引到 Elasticsearch 中时保持统一。


这种分段是 CouchPotato 最初的特性之一,因为我们用它来实时记录辩论内容。通常情况下,在竞选活动中,会有一群实习生观看辩论,并把辩论内容打出来。但我们没有一大批实习生来做这个事情,所以就有了 CouchPotato。


不过,分段带来了顺序问题。有时候,Transcribe 会在前一个片段完成之前完成后一个片段的 ASR,这意味着所有需要异步完成的工作在处理完毕之后需要按照正确的顺序重新编译。对我来说,这听起来就像是一个反应式编程问题。


我们花了很多时间来解决异步处理事件的顺序问题。这很复杂,但我们做到了。


这个时候,DocsWeb 就派上用场了。DocsWeb 将 CouchPotato 的片段转录输出发送到 Google Doc,让我们可以几乎实时地与竞选活动的其他成员分享转录文本——除了从 Transcribe 到 Elasticsearch 有点延迟,但这并不算太糟。我们记录下了每一场辩论以及大量其他媒体内容,这些内容需要一群实习生花上一辈子的时间才能完成。


解决这些片段的顺序问题,其中有一部分工作是弄清楚如何替换 CouchPotato 实例——比如,在部署期间或实时转录事件已经在运行的时候。关于这个话题还有很多要说的,比如我们如何制作音频帧拼接,以便可以逐步淘汰旧的实例,并逐步引入新的实例。这涉及了太多的内容。要知道,HotPotato 做了很多工作,让我们可以在零部署和零状态损失的情况下对 CouchPotato 进行热部署。


KatoPotato 是整个架构的切入点。它是一个编排引擎,协调 CouchPotato、DocsWeb 和 Elastic 之间的数据移动,并充当启动 CouchPotato 工作负载的主要 API。此外,它还负责监控 CouchPotato 的状态,并决定 HotPotato 是否需要启动新实例。


有时候,Linux 上的音频捕捉会罢工。CouchPotato 能够向 KatoPotato 报告它是否真的在捕捉音频。如果它没有在捕捉音频,KatoPotato 可以启动新的 CouchPotato 实例,并通过 HotPotato 进行替换。


CouchPotato 是一个建立在云机器学习之上的平台,可以让我们快速了解多媒体内容,不必花费宝贵的人力时间在这样的任务上。这是一个伟大的工程,我很高兴它能够为我们带来价值。

结论

关于我们所构建的技术,还有很多其他东西,比如关系组织应用程序、将 S3 和 RDS 连接到 Redshift 的数据管道,或者我们在整个过程中创建的微型网站。我还可以分享我们是如何在一个快节奏和充满活力的环境中合作的。


我已经分享了一些我们为 2020 年总统竞选所做的最有趣的架构。很高兴能与大家分享这些,我也期待今后能与大家分享更多内容。


作者简介:

Dan Woods 是 Shipt 的首席信息技术官和网络安全副总裁。在担任 2020 年总统竞选首席技术官之前,他是 Target 的一名杰出的工程师,专注于基础设施和运营,构建大规模、可靠的分布式系统。在加入 Target 之前,他参与了 2016 年希拉里竞选团队的技术平台工作。在参与总统竞选技术工作之前,Woods 曾在 Netflix 的运营工程部门担任高级软件工程师,并帮助创建了 Netflix 的开源持续交付平台 Spinnaker。Woods 还是 Ratpack Web 框架的开源团队成员。他是《Learning Ratpack》(于 2016 年由 O'Reilly 出版)一书的作者。


原文链接

Building Tech at Presidential Scale

2021-11-03 14:423578

评论

发布
暂无评论
发现更多内容
2020年美国大选技术平台架构_架构_Dan Woods_InfoQ精选文章