30 秒看懂
Maude Lemaire 与 Gergely Orosz 讨论在 Slack、GitHub 和 Cursor 的经验。她描述过去的架构和事故,解释使用模式如何影响负载测试,并主张工程师验证 AI 生成的工作,保持对产品需求的理解。
- 1迁移在线数据Slack 在保留旧读取路径时使用双写、回填和影子读取。
- 2表情回应引发的惊群一条热门消息可能触发大量频道读取和表情回应扇出。
- 3更轻量的负载测试Go 进程模拟 WebSocket 连接和 API 调用,无须为每个用户运行浏览器。
- 4分片与散射查询Lemaire 回忆,GitHub 当时的 16 分片方案受到跨多个分片查询的限制。
- 5验证时序图她把 AI 生成的时序图当作起点,结合代码逐项标注。
- 6跨团队轮岗产品与平台工程师可以通过共同工作和轮岗相互学习。
要点建议
- 安全的数据迁移可以结合最小访问层、功能开关、双写、回填和影子读取。
- 负载测试应模拟实际产品流程及重要的故障模式。
- 客户端事件洪流和服务端惊群相关,但并不相同。
- 散射查询可能使增加数据库分片变得昂贵且困难。
- AI 可以辅助探索,但性能调查仍需要测量、上下文和验证。
- 产品与平台工程师可以通过轮岗和共同承担可靠性责任相互学习。
按章节阅读整理后的全文
从生物学到软件
Lemaire 讲述自己进入工程行业的经历和早期工作。
Gergely Orosz 介绍首席工程师、《Refactoring at Scale》作者 Maude Lemaire。两人讨论 Slack 和 GitHub 的扩展、负载测试、数据库迁移,以及她在 Cursor 调查性能问题时如何使用 AI。
Lemaire 从小接触计算机,她的父亲教授计算机科学。但她最初计划研究遗传学,上大学时选择了微生物学,并未认定自己会进入软件行业。
她意识到,擅长记忆与喜欢记忆是两回事。考虑转学工程时,她选修了计算机科学入门课,发现自己喜欢通过编程让计算机完成任务。
她的第一份工作在 Rent the Runway,结合了编程与时尚两个兴趣。她很欣赏工程负责人 Camille Fournier;后者后来帮助她获得了 Slack 的机会。
Orosz 回忆约 2016 年为一家大型公司评估消息系统的经历。这为讨论提供了背景:适合较小团队的产品,在单个客户需要数万人同时连接时可能遇到不同的限制。
Slack 的企业级扩展
她解释按团队分片、企业分片热点和频道数据迁移。
在 Slack,负责帮助 Lemaire 入职的同事带她接触性能工作。她说,早期许多改进都在重新处理创业阶段有意识采用的捷径:它们当时帮助团队快速前进,随着使用量增长却变得昂贵。
Slack 准备推出企业产品时,IBM 是较早的大客户。随着采用规模扩大,公司组建了专门的企业性能团队;Lemaire 加入团队,向更资深的工程师学习。
她介绍的是当时的架构,并不一定代表今天的 Slack。数据按团队或工作区分片;大客户可以使用更大的专属数据库,小客户共享实例,但最终可购买的最大机器也会成为限制。
WebSocket 连接也与客户的服务器关联。繁忙组织可以分配专属聊天基础设施,但企业级使用挑战了“把大公司简单拆成小工作区即可”的假设。
Slack 在工作区之上增加企业实体,让同一公司的人跨团队协作。这也形成热点:企业级私信和大型共享频道使许多用户同时查询同一个企业分片。
即使是填充用户侧边栏,也涉及多种数据表示:公开频道、私密频道、私信和群组消息曾分别存储。客户规模扩大后,连接这些表的成本随之上升。
一位处理通知计数的同事认为,渐进式调优已不够,需要统一数据。Lemaire 主动承担迁移,而旧表仍在为生产流量提供服务。
PHP 代码库在许多过程式调用位置直接包含 SQL,而不是统一放在常见 ORM 后面。她找到 400 多个相关调用,需要在不悄悄改变行为的情况下修改它们。
她首先把现有查询移入命名清楚的函数,保留原有行为,而不是同时进行优化。这个最小数据访问层让后续迁移更容易管理,并用功能开关控制各项变化。
迁移通过双写和回填填充新表,再用影子读取比较新旧结果,同时生产仍使用旧路径。切换之前,仪表盘持续跟踪差异。
内部发布时,她发现差异并重新执行熟悉的删除和回填流程,却忘了同事已经开始读取新表。Slack 员工一度看到空白侧边栏;她把读取切回旧数据,等待回填完成。
惊群与事件洪流
两人讨论不同故障模式及其对用户的影响。
谈到负载测试,Lemaire 首先关注产品的真实使用模式和可能的故障方式。Slack 的一个问题是惊群:大量用户几乎同时对同一事件作出反应。
她举例说,CEO 在有 10 万活跃用户的频道发布好消息。许多接收者在数秒内打开频道、读取历史并添加回应;每个回应又可能扇出到大量已连接客户端。
在高负载下,Slack 会区分事件优先级:文字消息比回应更重要,因此部分回应事件可以丢弃。Lemaire 认为,这既是工程决定,也是产品判断。
她还质疑一条消息是否需要无限增加回应。她说 Slack 限制了不同表情的种类,但仍允许同一表情获得更多回应;决定用户可以失去什么,需要产品负责人和具体场景。
事件洪流与惊群不同:前者是某个客户端被收到的事件淹没。两者可能同时发生,但事件洪流中的故障单位是接收端客户端。
她回忆,一位 IBM 管理员登录许多工作区,由于连接未去重,同一企业消息可能被重复接收。客户端因此可能无法使用,尽管他是产品最积极的用户之一。
建立真实的负载测试
Slack 用更轻量的模拟客户端和工作流记录器替换高成本无头浏览器。
为了准备迎接预计约 50 万用户的客户,Slack 需要包含实时 WebSocket 连接的测试。只测试 API 的负载测试能覆盖数据库请求,却会遗漏客户端事件交付和后续反应。
较早的方案是在 Kubernetes pod 中运行大量无头 Chrome 实例和 Slack。Lemaire 说,这种方式接近真实使用,但成本高且运维脆弱:团队花了不少时间恢复崩溃的 pod,而不是运行目标场景。
她给出的数字是,每个无头实例运行五小时约 37 美分;主持人据此估计目标规模下总成本非常高。这是访谈中的历史近似估计,并非当前云服务价格。
替代方案使用轻量 Go 进程,维持 WebSocket 连接并发出具有代表性的 API 请求。它牺牲了部分浏览器层面的真实性,但以更可行的资源成本覆盖了团队关心的路径。
模拟还包含对边缘缓存的请求,后者用于延迟敏感的数据。Lemaire 强调,有用的测试需要模拟真实路径,包括事件交付以及事件到达后触发的操作。
团队逐步把工具发展为可供模拟用户执行的例程。Lemaire 建立了记录器,捕获真实产品流程中的 API 调用及进出 WebSocket 的消息,再把选定事件转成可重复脚本。
她希望产品经理亲自记录重要工作流,交给性能团队定期测试。产品专家了解功能的实际使用方式,可以发现平台工程师可能忽略的场景。
GitHub、Vitess 与散射查询
Lemaire 讨论历史上的分片限制及大型 Rails 单体的挑战。
Lemaire 于 2024 年加入 GitHub,当时公司正应对增长的负载,并把更多基础设施迁向 Azure。一位同事告诉她物理容量受到限制,因此挑战既包括迁移,也包括更高效地使用现有资源。
她曾参与 Slack 从按团队分片转向在 MySQL 上使用 Vitess 的更动态方案。频道可能比整个大型团队更适合作为分片单位,但合适的键取决于访问模式。
在 GitHub,她当时发现拉取请求和问题数据只有 16 个分片。她原本预期数量更多,便询问原因;答案涉及必须访问多个分片的散射查询。
如果查询缺少路由到目标分片所需的信息,就可能必须搜索每个分片。她用查找某用户的拉取请求作假设例子,并明确说自己不知道该具体查询是否真的会散射。
更多分片可以改善数据分布,但散射查询也会访问更多位置。Lemaire 最初希望消除散射查询,却发现大型 Rails 单体中的工作比在其他环境中套用同一方案困难得多。
与她习惯的显式 SQL 相比,Active Record 让底层数据库行为不那么容易看见。她描述了与一位经验丰富的 Rails 工程师结对,追踪一个生成查询却难以定位的小函数。
她担心,抽象可能让人很容易添加代码,却看不到它触发的数据库工作。她也承认单体架构支持了大量增长;难点在于安全地改变长期形成的访问模式。
GitHub 的内部调试视图会显示渲染页面所用的查询和集群。Lemaire 回忆,她最后查看时,一个仓库页面需要跨至少三个集群执行 100 多次 MySQL 查询;这是她当时的观察,并非当前测量。
她质疑,尤其在数值很大之后,是否每个可见计数都需要实时计算。产品要求会影响缓存选择,因此适当取舍取决于用户究竟需要哪些精确数字。
借助 AI 调查性能
她解释首 token 延迟、追踪,以及为什么需要验证模型输出。
谈到 AI,Lemaire 说它对实现的帮助大于对性能优化调查的帮助。在 Cursor,她研究首个可见 token 的时间,这取决于请求到达模型提供方之前和之后的多项工作。
准备上下文、缓存决策以及经过推理代理的路径都会影响延迟。由于产品、隐私、负载和成本约束,一些数据不能或不应无限期缓存。
她认为语言模型适合基础埋点,但在异步流程中选择该测量什么时不够可靠。她也使用变异测试挑战生成的测试,避免测试只是验证与其同时生成的实现。
她说,Cursor 同时存在过多和过少有用追踪的问题:包含数百万 span 的追踪难以使用,而在不同位置不一致地采样又可能丢失所需信息。她手动检查流程和埋点,理解同步与异步工作。
她让模型生成从提交提示词到首个可见 token 的大型时序图,打印出来后边读代码边标注。图只是辅助起点;她亲自核对依赖关系与正确性。
一个建议的优化是并行执行任务。Lemaire 说,如果很少有用户需要其中一些任务,而一个长任务仍主导延迟,这未必有用。她认为,在合适范围内延长缓存 TTL 等更简单的变化可能更有效。
她整天都会用语言模型探索问题和处理常规工程任务,但会手动验证重要结果。她担心平台基础必须覆盖整个问题,而不只是其中最容易解决的部分。
连接产品与平台
访谈以轮岗、护栏和共同维护可靠性的建议结尾。
对于想从事平台工作的工程师,她建议在产品团队和平台团队之间交流或轮岗。在产品工作中反复看到同一个问题,可能揭示共享解决方案的机会;轮岗也让平台工程师贴近真实使用。
她认为,当产品团队借助 AI 更快交付时,更强的平台护栏尤其有价值。Orosz 总结了双向学习的经验:理解客户需求、性能和可靠性,并跨团队协作,而不是把双方当作彼此隔绝的世界。
同频道的其他文章
1:41:17EN → 简体中文
1:56:28EN → 简体中文
1:34:17EN → 简体中文
1:59:04EN → 简体中文
29:39EN → 简体中文
1:42:31EN → 简体中文