5个月从0到1,Meta如何利用单体架构实现Threads...

程序员咋不秃头 2024-09-11 01:38:39

2023 年 1 月,我们获悉必须在短短数月内打造一款微博服务,以期与 Twitter 一较高下。为了应对这一挑战,我们迅速组建了一支精干的团队,并在 7 月份成功推出了一款全新的社交网络应用。本文将回顾我们去年在 Meta 如何开发并上线了 Threads 应用。

本文是对我在 2024 年伦敦 QCon 大会上所做演讲 “从 0 到 1——5 个月交付 Threads 应用” 的总结。

价值和里程碑

新的 Threads 应用将为用户提供四个基本价值。

首先,我们强调文本内容。与 Instagram 将媒体内容作为核心不同,Threads 的每一篇帖子都从文本开始。

其次,我们希望延续 Instagram 的设计语言和精髓。Instagram 之所以受到全球众多用户的喜爱,其简洁性与产品质感功不可没。我们觉得这是一个很好的基础。

第三,我们知道早期 Twitter 确立其地位的一个价值是开放性。我的意思是,社区可以自由地使用 API 来创造个性化的体验。公共内容通过网页嵌入的方式变得广泛可及。人们通常使用这些工具在各个地方分享他们的 Twitter feed。尽管我们正步入一个由生成式 AI 引领的新时代,但我们坚信,封闭花园式的产品设计已不再适应潮流。

最后,我们认为我们需要优先考虑创作者的需求。在每个社交网络中,总有一群用户,他们创作了大部分其他人消费的内容。这种现象通常遵循 Zipfian 指数分布。在以文本为主的社交网络中,这一现象更加显著,因为生产大部分内容的用户群体比例更小。要在有限的字数(如 500 字)内创作出既有趣又吸引人的内容,无疑是一项挑战。我们深知,充分考虑并满足这个群体的需求对于实现长期的成功至关重要。

基于这些价值主张,我们勾勒出了绝对最小产品(MVP)的蓝图,并开始着手构建。我门的一个关键目标是尽快推出一个可交付的产品,这样就有选择的余地。

为了给自己设定明确的目标,我们详细规划了四个期望达成的里程碑。每个里程碑都被设计成一个潜在的完成状态,也就是说,在必要时,我们可以在达到每个里程碑时选择发布产品。每个里程碑都逐步引入下一个最关键的功能。

第一个里程碑只构建最基础的应用。它看起来非常简陋,用户可以登录、发表一个纯文本的帖子,并将这些帖子与他们的账户关联起来。

第二个里程碑是为应用程序添加基本要素。在这个阶段,我们为应用程序添加熟悉的样式,有用于浏览动态、查看通知和访问个人资料的标签。让用户验证、阻止功能和报告功能发挥作用。

第三个里程碑是我们所说的“精简启动候选”阶段。在这个阶段,我们专注于完善那些之前可能被忽视的服务功能,例如人物搜索功能,以及引入全屏查看器来更好地查看照片和视频。我们开始深入探索如何管理对话内容,这是应用程序的核心。如何将它们作为单元进行排序?从 Instagram 复制关注内容,这样就可以快速设置个人资料。这是一个包含了多项改进的清单。

第四个里程碑是实现与 Fediverse(联邦宇宙)的互操作性,这标志着我们的产品接近最终的发布候选状态。对于那些了解这款产品的人来说,我们的雄心壮志看起来可能有些不切实际,因为即便到了今天,我们也没有完全实现与 Fediverse 的互操作性。但因为太过于乐观,我曾承诺我们能在一个月内完成这项工作。

随着每个里程碑的临近,我们的心态从专注于构建功能转变为精心打磨产品,以便为发布做好准备。对于工程师来说,这种转变实际上是相当耗费精力的,因为在构建和修改之间频繁切换令人感到疲惫。在某种程度上,我们在那六个月的时间里发布了三个不同的产品版本。每次发布前,我们都会组织一个紧急会议,团队成员们熬夜工作,全力以赴地推动一个完整的应用程序达到发布标准。然后,我们会集体决定是否已经准备好将产品发布出去。

事后看来,这种策略带来了一个显著的优势:作为一个强有力的简化工具。如果你只有三周时间来决定哪些功能是必须添加的,哪些能够带来最大的增量价值,你就不得不将选择范围缩小到最核心的要素。我们最终发布的产品可以看作是 3.5 版本的里程碑。虽然我们从未达到 4.0 版本的里程碑,但确实在 3.0 版本的基础上实现了一次非常关键的迭代。

加快开发速度

在短短五个月内从零开始开发 Threads 无疑是一项雄心勃勃的挑战。我们的项目于二月份正式启动,并向领导层做出了夏季前准备就绪的承诺。我们的信心源于我们知道我们可以很好地利用 Instagram 已有的一些东西。

从宏观角度看,Instagram 上的分享功能非常直观。用户可以关注感兴趣的个人资料,浏览他们的帖子,同时系统还会推荐相关内容。用户之间可以互动,围绕共同兴趣构建社区。有趣的是,这些功能正是我们在 Threads 项目初期想要实现的,因此我们巧妙地重用了它们。

我们的第一个原型在 Instagram 原有的动态信息流中引入了一个模块,用于展示纯文本帖子。我们重用了已有的排名机制。对于帖子的布局,我们内部开玩笑说,我们只不过是重新排列了一下。我们将标题置于顶部,而将内容则置于下方,其余部分保持不变。这样的变化显著降低了技术实现的复杂性。

我们成功地将构建一个全新的基于文本的社交网络的复杂问题转化成一个具体的问题,即如何定制 Instagram 的信息流来展示新的文本帖子。

作为工程师,你可能会意识到这种方法存在一些缺陷。当你利用已有的代码库来构建新功能,你可能会积累大量的技术债务,尤其是如果这个代码库并非为新的服务而设计。这将导致一系列小问题的出现。此外,你还需要对庞大的遗留代码库有深入的了解,它可能包含数百万行代码,但你真正需要定制的只是其中的一小部分。对于这一点,我喜欢引用一句话:“阅读别人的代码比编写自己的代码要困难得多。”

我们借鉴了 Instagram 的设计,并始终坚持这一原则,尽可能地进行精准的复用,只在必要时才进行重新构建。

这也意味着对于 Threads 团队来说,有很多值得感激 Instragram 的地方。Threads 在很大程度上得益于 Instagram 基础设施和产品团队多年来打下的坚实基础。没有这些基础,我们的成就将无从谈起。我倾向于认为,我们对简洁性的追求已经得到了回报。我们在发布时收到的许多赞誉,正是因为应用程序的简洁明了,但又不会让人感觉缺少基本的功能。

Threads 的技术栈

以下是 Threads 技术栈的概览。

Meta 通常非常重视单体二进制文件及其单体代码库。这样做有着多重考量。其结果是,Instagram 的大部分业务逻辑都集中在一个叫作 Distillery 的 Python 二进制文件中,这个文件与 Meta 更大的单体——一个庞大的 PHP 或 Hack 二进制文件 WWW——通信。Distillery 可能是世界上最大规模的 Django 部署之一,我不知道我们是否应该为此感到自豪,尽管我们运行的是一个定制版本。

我们用户的数据被存储在多个系统中。其中最关键的是 TAO(一个写入缓存系统,基于图数据模型)和 UDB(一个分片的 MySQL 部署,几乎包含了我们所有的数据)。TAO 天生就擅长处理节点之间的链接,并且拥有优化的操作来查询这些链接的细节。此外还有一个索引系统,你可以标记特定的链接和你希望怎样查询它们。这些索引被放在内存中,可以提供快速的查询支持。整个模型是 Meta 多年社交产品构建经验的结晶,对我们非常有用。

我们的架构还涉及了其他一些重要的系统,我无法在此一一详细说明。例如,我们有一个大型的 Haskell 服务,它负责处理我们决策过程中的许多规则,包括识别用户行为中的异常模式。我们有一个叫作 ZippyDB 的键值存储来存储大量瞬态数据,这些数据的写入频率极高,超出了 MySQL 的处理能力。我们还有一个无服务器计算平台,它支持异步操作,这一点非常关键,我稍后会介绍。最后,我们还有一个类似于 Kubernetes 的系统,负责管理、部署和扩展所有这些服务。所有这些系统都必须协同工作,以确保整个平台的高效运行。

发 布

7 月 5 日,非工程师团队在产品上与早期使用这款产品的名人愉快互动,这或许是他们与夏奇拉亲密对话的难得机会。与此同时,工程师们全力以赴为次日的产品发布做准备:给系统括容,精心规划发布前的演示,确保一切准备就绪。

当天,我们的一位数据工程师在聊天中突然插话,提到了一些异常情况。他发现我们的应用程序记录了数万次登录失败的尝试。这很奇怪,因为理论上还没有人——更不用说数万人了——能够访问我们的应用程序。我们迅速调整方向,排除了数据出错的可能性。随后,我们注意到这些尝试都来自东亚地区。你可能已经猜到了,这实际上是一个时区问题。具体来说,我们利用了 App Store 的预购功能,允许用户在应用程序正式发布时注册下载。你可以指定一个日期。我们设定的是 7 月 6 日,这意味着这些国家在午夜之后应用程序就会变得可用。然而,由于我们这边的访问限制还没有放开,所以他们无法登录。这是一个尴尬的时刻。

那种在内部有限测试中所感受到的安全感已经荡然无存。我们迅速组建了一个紧急战情室,并召开了一个 Zoom 电话会议,召集了来自公司各地的近 100 名专家,他们分别代表了之前提到的各种系统。考虑到这是那些国家的深夜,我们清楚地意识到,一旦服务全面上线,实际需求将远远超出我们的预期。

我们已经积累了一大批预购用户,他们将在当地时间午夜之后访问应用程序。为了应对这一挑战,我们重新选定了一个目标发布时间,特别选择了英国时间的午夜,这为我们争取到了宝贵的几个小时准备时间。在这段时间里,我们扩大了所有 Threads 服务所涉及的系统容量。对信息流功能至关重要的 ZippyDB 缓存系统需要进行重新分片才能应对预期流量的激增——它需要处理的容量是当前配置的 100 倍。这项紧急任务在马克宣布 Threads 开放注册的几分钟前才完成。我想,我永远也不会忘记那种紧张到最后一刻的感受。

一个挑战是将 Instagram 的关注者网络复制到 Threads 上。这里的问题在于,用户可能想要关注那些尚未注册 Threads 的人。这导致了一个问题:等待某些知名人士(比如前总统奥巴马这样的大名人)注册的人数数量庞大,他们的粉丝数量都以百万计。我们最初设计的系统显然无法应对这种规模。为了解决这个问题,我们迅速重新设计了那个系统,让它能够水平伸缩并形成工作节点集群,从而能够处理这些账户背后的庞大关注队列。

这几天的经历令人难忘,我相信我可能再也不会遇到如此紧张的产品发布过程了。我从他人身上学到了很多关于如何保持冷静和优雅的宝贵经验。无论我未来走到哪里,这些经验都将是我宝贵的财富。

结 论

总的来说,启动这个项目对我来说是一次非常独特的体验。我最大的收获是认识到保持事物简单的重要性。这当然不是一件容易的事。那句关于写一封更短的信需要花费更多时间的格言,适用于任何创造性的工作。如果你清楚自己想要提供什么样的价值,它就能指导你在需要做出艰难决策时如何精简和聚焦。

另一个深刻的教训是,更干净、更新的代码并不一定总是更好的。所有这些细微的洞见都融入了一个经过实战考验的旧代码库中。如果有可能,不要轻易丢弃这些东西。与此相辅相成的是我们的信条:“代码胜于雄辩”。通过构建产品来实际解决问题,通常比进行抽象的分析更能有效地回答疑问。我们通过原型而非幻灯片更快地解决了很多棘手的问题。

当然,我们所取得的成功不能一概而论,因为我们必须认识到,我们对机会的把握以及产品发布后市场的反应可能是因为我们的运气。这一切都无法事先得到保证。我非常感激那些接受我们产品的社区成员。我们有一个说法,可以追溯到 Facebook 的早期,那就是这段旅程只完成了 1%。对我来说,尤其是对 Threads 而言,这种感觉尤为真切。

查看英文原文:

https://www.infoq.com/articles/shipping-threads-5-months/

0 阅读:0