Simon & Sam: 数据库、可靠性与闲聊

来源: Twitter/X Broadcast 嘉宾:

  • Simon Eskildsen (@Sirupsen) — Turbopuffer 联合创始人兼 CEO,前 Shopify(从 1K 扩展到 1M RPS)
  • Sam Lambert (@samlambert) — PlanetScale CEO,前 GitHub VP Engineering
  • Ben (PlanetScale) — 主持人 日期: 2025 年 时长: ~75 分钟(已全部转录)

核心话题

1. Napkin Math 项目 — 性能建模的重要性

  • Simon 维护的 Napkin Math 项目:记录各种基础设施的延迟/带宽数据(对象存储延迟、NVMe SSD 带宽等)
  • 核心观点:Profiling 只能优化几个百分点;要获得真正的性能提升,需要坐下来构建模型,把数字乘在一起,看看系统表现距离底层硬件的理论极限有多远
  • Simon 的梦想:Napkin Math 每天在所有现代机型上自动运行基准测试(类似 Lucene Benchmarks),生成延迟直方图
  • Simon 和 Sam 都表示愿意联合赞助有人把 Napkin Math 做到下一个级别
  • Turbopuffer 的设计灵感正是来自于对这些底层数字的深入理解

2. S3 架构深度解析

  • S3 内部架构(Simon 的理解):
    • 请求 → Proxy 层 → 元数据层(记录文件块位置)→ 分布式存储层
    • 使用 Parity Encoding,一个块可能分布在多个节点
    • 底层块大小估计 1-4 MB
  • 关键洞察:元数据层 vs 存储层延迟差异巨大
    • S3 元数据层 P50 ≈ 8ms
    • GCS 元数据层 P50 ≈ 14-18ms(因为 Spanner 前端,跨 3 个 AZ)
    • Azure 元数据层 P50 ≈ 4-5ms(最快!)
    • 存储层 P50/P99 差异大:HDD、大规模分布式系统、高利用率
  • ETag/条件请求只触及元数据层,可用于低延迟一致性检查

3. Turbopuffer 的架构设计哲学

  • 核心设计约束:每个计算节点都可以随时死掉,不丢数据 → 完全依赖对象存储做持久化
  • 强一致性选择:与 Elasticsearch 等最终一致性搜索系统不同,Turbopuffer 选择强一致
    • 写入后立即可查询(不像 ES 默认需要等待段合并)
    • 代价:每次查询需要访问对象存储确认一致性(8-15ms)
    • 对搜索场景可接受(P99 50ms 在搜索领域完全 OK)
    • 可选关闭一致性检查,直接从缓存返回(~1ms)
  • 为什么这个架构对搜索是 feature 但对 OLTP 是 bug
    • OLTP 每个页面加载 = 数百次查询,5ms 地板延迟会拖垮整个应用
    • Shopify/GitHub 这种 Rails 应用需要 ~500μs 级别的数据库延迟
    • 搜索系统可以容忍更高延迟,但获得了免费的持久性和可靠性

4. 数据库对产品的极端重要性

  • Sam: 数据库挂了 = 产品挂了,没有中间状态
    • 即使只是只读模式,用户也无法改权限、删员工等 → 产品实质不可用
    • 网页上每一个元素都来自数据库:session、时间线、通知、关注列表……
    • 没有数据库,产品就是空模板
  • 持久性同样关键:丢数据比宕机更可怕(“丢了别人的 Strava 数据”)

5. OLTP 数据库的缓存与故障切换

Buffer Pool 预热问题

  • 故障切换后缓存不对 = 性能断崖
    • Shopify 分片故障切换后,繁忙分片可能慢几分钟
    • 解决方案:镜像读查询,让缓存达到正确平衡
  • PlanetScale 的做法
    • 计划性故障切换:提前预热目标节点
    • 预热方式:发送相同查询直到延迟收敛
    • 曾经用 shell 脚本 + tcpdump 抓查询来预热(很 hacky 但有效)
  • MySQL 特有优势:Buffer Pool Saving
    • 可以把 LRU 列表保存到磁盘,恢复时直接加载
    • PostgreSQL 没有这个功能
    • Sam 认为 PlanetScale 应该更好地展示这些复杂性给用户

缓存层选择:Memcached vs 读副本

  • Simon 更偏好读副本而非外部缓存(Memcached)
    • 外部缓存的危险:从缓存拿到过期数据 → 写回数据库 → 数据污染
    • 缓存没有 “五个 9” 的一致性保证
    • 读副本更容易推理(虽然需要处理复制延迟)
  • 读副本的挑战
    • 需要在写入后短暂路由到主库(Memcached 里设标记,10 秒后过期)
    • 需要标记从副本返回的对象,防止写回
    • 复制延迟高时需要告警和限流

控制复制延迟

  • Shopify 方案:所有后台维护任务表达为枚举器,每批处理后检查复制延迟和 InnoDB 线程数
  • 延迟过高则 sleep 等待
  • 效果非常好,能精确控制复制延迟

6. Shopify Storefront 重写

  • Simon 和 Justine(Turbopuffer 联合创始人)在 Shopify 重写了整个 Storefront
  • 背景:Liquid 模板语言 → 动态渲染 → 查询瀑布依赖问题
  • 核心优化
    1. 全页缓存到 Memcached
    2. 预测性查询预加载:缓存上次渲染的 SQL 查询列表,在请求开始时并行发起,渲染时 resolve futures → 消除瀑布
    3. 提取为独立服务,脱离主 Rails 应用
  • 验证策略(“JIT Render”)
    • Nginx 前端同时发送请求到新旧系统
    • 比较 HTML 输出,一致则切流量到新系统
    • 用百分比图表跟踪兼容性进展
    • 处理百万种不同模板 + 用户依赖 bug 的兼容性
  • ~1.5 年后承载 95%+ 流量(约 2019 年开始)
  • Simon 最初对大重写持怀疑态度,但最终效果很好

7. 招聘小故事

  • GitHub 早期支持团队第一个 hire 是 Tekkub(WoW 插件作者),在 GitHub IRC 帮助社区被注意到
  • PlanetScale 也用类似方式:从 Discord 社区里招了一个一直在帮忙的工程师
  • 启示:参与社区、贡献开源库是获得工作的好方式

金句

“如果你只是跟自己赛跑,你永远不知道底层机器真正能做到什么。” — Simon,论 Napkin Math 的重要性

“数据库挂了,产品就是一个空模板。” — Sam,论数据库的重要性

“构建一个不丢数据的可靠存储引擎需要 5-10 年。我们完全搭载在对象存储上,所以不需要做这件事。” — Simon,论 Turbopuffer 架构

“这个架构对大多数 OLTP 系统是 bug,但对 Turbopuffer 是 feature。” — Sam,论 disaggregated storage


关键数字

指标数值
S3 元数据层 P50~8ms
GCS 元数据层 P50~14-18ms
Azure 元数据层 P50~4-5ms
OLTP 可接受延迟~500μs
搜索可接受 P99~50ms
Shopify 故障切换缓存预热数分钟
Storefront 重写承载流量>95%(~1.5 年后)

后半段内容(38:00 - 75:00)

8. 多数据中心与 Active-Active

  • Simon 的核心观点:你不需要 Active-Active
    • Active-Active = 多个数据中心同时服务生产流量,工程成本巨大
    • 多数据中心主要是为了防自己的故障,而非云厂商故障
    • 云厂商骨干网故障时,故障切换也帮不了你
  • Shopify 的演进
    1. 第一阶段(IPO 前):Chicago 主 + Ashburn 备,硬件闲置,20 点 spreadsheet 手动切换
    2. 第二阶段(2015,Pods):每个分片成为独立 Pod(数据库 + 缓存 + 所有层级)
      • 128 个 Pod 可以独立在不同数据中心运行
      • Slack bot 执行切换,几秒暂停写入,读取基本无中断
      • Nginx Lua 做请求路由(Nginx Lua 是万能工具)
    3. Storefront 后来分离出去,可以在更多区域服务
  • 对分布式共识数据库(Spanner 等)的批评
    • Simon: “我花了一辈子做数据库,但我不理解这些系统。我不理解时钟怎么工作。”
    • 凌晨 3 点没人能理解分布式事务失败的原因
    • 最终一致性比分布式事务失败更容易处理
    • Google 为 Spanner 在数据中心放原子钟 → “如果你闲着没事,挺有趣,但是…”
    • Sam: “复杂性商人们”把简单问题卖复杂了

9. 数据库可靠性与行业批评

  • Sam 为什么开始公开批评竞品宕机
    • 以前行业有不成文规矩:不公开批评别人的故障(“downtime shaming”)
    • Sam 以前也遵守,但现在改变了立场
    • 原因:当前 AI hype 周期太疯狂,营销预算巨大,言辞已失去意义
    • 某些平台持续可用性问题,甚至不更新状态页,用户只能在 Twitter 上报告
    • 同理心转向用户:有慈善机构无法配送食物,有创业者因此可能丢掉六位数客户
    • PlanetScale 帮助数百用户快速迁移,发放大量信用额度(来自利润而非 VC 资金)
  • PlanetScale 的可靠性文化
    • ~60% 路线图用于可靠性工作
    • 每次事故后大量修复工作,甚至在影响用户前就宣布事故
    • 可靠性可以吞噬功能开发,但反过来不行
    • 定期发布 “Code Red” 来纠正偏差

10. 创始人-市场契合度与诚实营销

  • Simon 的顿悟:创始人最大优势是对问题领域的校准权重
    • 经历多次迭代和失败后才确信:自己的判断方向是对的
    • Turbopuffer 做过一些违背直觉的决策(如果早点相信自己就不会)
    • 现在的态度:“盈利公司,按我的方式来,信任它或者找别人”
  • 运营文化无法后天培养
    • 如果创始团队没有运营文化,公司永远不会有
    • 在 Shopify 见过太多失败案例:纯工程师团队接手运营,项目失败
    • 代码成本趋近于零的时代,运营能力更加稀缺和宝贵
  • 诚实网站的哲学
    • 两家公司网站都是:这是产品,这是价格,这是它不擅长的
    • Turbopuffer 网站有整页的限制说明
    • 会因此丢客户,但客户也会在功能上线后回来
    • “工程沟通就是尽可能快地把心智模型传递给别人,减少解读开销”

11. Logo 与品牌信任

  • Turbopuffer 只在客户真正在生产环境使用后才放 Logo
    • Anthropic logo:从首次请求到上网站 > 1 年
    • Atlassian、Notion 同样如此
  • Logo 滥用问题严重:有公司放了某客户 Logo,实际只是某个开发者注册了账号
  • 游戏公司 Logo 的特殊风险:
    • AAA 游戏公司警告 Sam:“你会收到死亡威胁”
    • 不是因为宕机,而是玩家对游戏决策不满时会攻击供应商
    • GitHub 曾因 GamerGate 相关事件员工收到死亡威胁

12. Redis HA 与工具选择

  • 观众问题:PlanetScale 会做 Redis HA 吗?
    • Sam: 最多请求的托管数据库是 ElasticsearchClickHouse(不是 Redis)
    • PlanetScale 做了 Postgres,下一步要能说服自己是做某产品的最佳团队
  • Simon 对 Redis 的建议
    • 尽量用一致性哈希的 Redis 集群,避免依赖 HA
    • 不要在 Redis 中存持久化状态(队列除外)
    • GitHub 曾因单线程 Redis 加载 80GB 数据导致 4 小时故障
    • Turbopuffer 完全不依赖任何外部数据库
  • Turbopuffer 用单个 JSON 文件在对象存储上做队列(因为不想引入依赖)

Takeaway