S
SkillNav

Vercel 如何把 Redirect 扩展到百万级:低延迟与低成本并存

深度2026-03-03T13:00:00+00:007 分钟阅读
Vercel 如何把 Redirect 扩展到百万级:低延迟与低成本并存

6 分钟阅读

2026 年 3 月 3 日

在小规模场景下,重定向(Redirect)很简单;但当规模达到数百万时,延迟和成本就会变成真正的系统工程问题。

此前在 Vercel,Redirect 主要通过 routing rules 和 middleware 处理。Routing rules 最多支持 2,000 条带通配符的复杂重定向,并按顺序逐条匹配执行。每条规则都可能涉及 regex 匹配,这意味着一次请求可能触发大量高成本计算。几千条规则时还能接受,但随着规则数量增长,请求侧工作量会线性上升。

Middleware 虽然更灵活,但会因为每个请求都要执行额外代码而增加延迟。为了在低延迟下承载数百万 Redirect,我们需要一条专用查询路径,让单次请求成本接近常数时间或对数时间。基于我们此前使用 Bloom filter 提升全球路由性能的工作,我们找到了将 Redirect 扩展到百万级的方法。

Link to heading我们优化的目标

  • 规模:

    • 每个项目支持数百万条静态 Redirect
  • 运行时行为:

    • 对未配置 Redirect 的项目不引入额外延迟成本

    • 提供快速的“no redirect”路径(因为大多数请求其实不会发生重定向)

    • 低进程内存占用,尽量依赖外部存储与缓存层

  • 工程价值观:

    • 相比过早优化,更重视简单性与可调试性

    • 采用迭代演进,而不是一开始就追求“完美设计”

基于这些目标,我们先从能想到的最简单方案出发:把 Redirect 数据和 Bloom filter 放在同一个文件里。由于 Redirect 数据本身就是 JSON,而 Bloom filter 也已支持导出 JSON,我们决定使用 JSONL 格式来存储。

Link to headingJSON 与 Bloom filter:和草稿纸估算的较量

Bloom filter 是一种概率型数据结构,用于判断某元素是否属于某个集合。它可能出现假阳性(false positive),但不会出现假阴性(false negative);因此它只能回答“肯定不在集合中”或“可能在集合中”。通过先检查一个小且可缓存的 Bloom filter,我们可以让不匹配的请求直接跳过 Redirect 查询,从而让最常见的“no redirect”路径成本极低。只有命中正例时才去解析 JSON 文件。

这个思路很简单,但能扩展吗?草稿纸估算的结论是:不行。100 万条 Redirect 很容易产生数百 MB 的文件,拉取并解析这么大的数据会直接击穿我们的延迟和内存预算。我们必须避免一次性加载全量数据集。

Link to heading分片 + Bloom filter:兼顾低内存与快速查询

解决办法是分片(sharding)。我们不再使用单个超大 JSONL 文件,而是对 redirect path 做哈希,将记录分散到多个小分片中。这样每个请求只需加载对应的一小块数据,把压力从进程内存转移到外部存储和文件系统缓存。Bloom filter 仍位于前置路径,为绝大多数流量做短路;而当请求通过 Bloom filter 时,我们也只需拉取并解析一个小分片,而不是整个 Redirect 集合。

Link to heading分片结构

每个分片包含 3 部分:

  • 一行 header,编码 Bloom filter 属性

  • base64 编码后的 Bloom filter

  • 一个以 src path 为 key 的 Redirect JSON 对象

示例:

code
{"version":"bulk-redirects","bloom":{"n":3,"p":1e-7,"m":102,"k":23,"s":0}}"Mec7FxGVcJ0fHdj8HA=="{"/old-path":{"destination":"/new-path", ...},"/another-old-path":{"destination":"/another-new-path", ...}, ...}

包含 header、Bloom filter 和 redirect map 的分片格式

在构建阶段,我们会生成所有分片及其 Bloom filter,并上传到外部存储。运行时,服务器只需在收到请求时知道该项目或部署对应哪个数据集、分片数量是多少。

Link to heading查询路径会先检查 Bloom filter,再决定是否解析 JSON

请求到来时,bulk redirect 查询流程如下:

  • 先检查该项目或部署是否配置了 bulk redirects。若没有,直接跳过并按常规流程处理。

  • 根据请求计算 redirect key,并哈希得到对应分片。

  • 从缓存或源站拉取分片,并检查 Bloom filter。

    • 若 Bloom filter 显示 key 不存在,则不解析该分片 JSON body。

    • 若 Bloom filter 显示 key 可能存在,则加载该分片 JSON body,并在对象中精确查找目标 Redirect。

这个设计有几个明显优点:

  • 负查询速度快: Bloom filter 很快,且可调到极低假阳性率

  • 分片可读性强: 分片就是 JSONL 文件,出问题时很容易 dump 出来逐项排查

  • 实现风险低: JSON 解析与 Bloom filter 都是简单技术,可快速上线并收集真实生产数据

Link to heading正向命中时,JSON 解析成为瓶颈

我们一开始就怀疑 JSON 解析会成为瓶颈,dogfooding 结果也证实了这一点。当 Bloom filter 提示某条 Redirect 可能存在时,解析该分片的完整 JSON body 会消耗明显时间。高 CPU 负载下还出现了明显延迟尖峰,因为 JSON 解析本身是 CPU 密集型任务,会与节点上其他任务争抢资源。

减小分片大小有助于提升解析速度,但更小分片会提高基数(需要管理的分片数量)并增加缓存未命中率。这形成了典型权衡:大分片带来更高 JSON 解析 CPU 开销,小分片则带来更多 cache miss 导致的 I/O 延迟。我们需要一种无需解析整个分片就能取到单条值的数据格式。

Link to heading基于有序 key 的二分查找,避免整片解析

我们不再把 Redirect 存成一个 JSON blob,而是实现了基于 redirect path 的二分查找。每个分片中的 key 按序存储,因此可以对 key 做对数时间搜索。找到目标 key 后,只需解析该条 Redirect 对应的 JSON。这样就绕开了分片大小问题。查询成本不再随分片总数据量增长,因此我们可以把分片保持在有利于缓存命中的较大尺寸,同时不再承担整片 JSON 解析成本。

code
{"version":"bulk-redirects","bloom":{"n":3,"p":1e-7,"m":102,"k":23,"s":0}}"Mec7FxGVcJ0fHdj8HA==""/old-path"{"destination":"/new-path", ...}"/another-old-path"{"destination":"/another-new-path", ...}

有序 key 让我们无需解析整个分片即可完成二分查找

Link to heading延迟下降,尖峰消失

当正向查询路径不再把 JSON 解析放在热路径后,命中 Redirect 的请求不仅更快,延迟也更稳定。

最直观的改善是高 CPU 负载下延迟尖峰被消除。过去解析完整 JSON 分片时,Redirect 查询会和节点上的其他任务竞争 CPU;改为二分查找后,单请求 CPU 成本下降到足够低,资源争用不再构成主要问题。

Link to heading为“常见路径”而设计

Redirect 本身并不复杂。真正的挑战在于:把这个简单抽象放进“数据量巨大、命中率低(多数冷数据)且边缘侧延迟要求严格”的环境里。Routing rules 并不是这类问题的合适工具。

因此我们构建了 bulk redirects 的专用路径:

  • 对 Redirect 数据做分片,保持每个数据块较小

  • 使用 Bloom filter,让最常见的“no redirect”请求足够便宜

  • 采用支持 key 二分查找的数据布局存储 Redirect

这轮开发再次强化了我们反复验证的一条原则:避免过早优化。先做简单、可调试的实现并打好观测,再让生产数据决定复杂度真正该落在哪些地方。

Link to heading开始使用 bulk redirects

Bulk redirects 已向 Pro 和 Enterprise 客户开放,可通过项目配置、dashboard、API 或 CLI 进行配置。当前限制为每个项目 100 万条 Redirect。如需更高容量,请联系我们

Plan

Included redirects

Additional capacity

Pro

每个项目 1,000 条

每增加 25,000 条,$50/月

Enterprise

每个项目 10,000 条

每增加 25,000 条,$50/月

你可以用 bulk redirects 管理大规模迁移、修复失效链接、处理过期页面等。详见bulk redirects 文档快速上手指南

原文链接:https://vercel.com/blog/scaling-redirects-to-infinity-on-vercel

相关文章

AINews:Harness Engineering 到底是不是一门真学问?
深度·3月5日
AINews:Harness Engineering 到底是不是一门真学问?

这篇文章围绕 AI 工程中的核心争议展开:系统能力究竟主要来自更强的模型(Big Model),还是来自更强的编排层(Big Harness)。文中汇总了 OpenAI、Anthropic、Scale AI、METR 等多方观点与数据,显示两派在“模型进步会不会吞噬 Harness 价值”上分歧明显。作者最终认为,随着 Agent 产品落地加速,Harness Engineering 的独立价值正在被市场和社区进一步确认。

10 分钟
每个 Agent 都需要一个 Box:Aaron Levie 谈 AI 时代的新基础设施
深度·3月5日
每个 Agent 都需要一个 Box:Aaron Levie 谈 AI 时代的新基础设施

在围绕“AI 是否正在杀死 SaaS”的争论中,Box CEO Aaron Levie 提出相反观点:企业内容与文件系统在 Agent 时代反而更关键。随着 Filesystem、Sandbox 和 Agent 工作流快速普及,核心问题从“让 Agent 能做事”转向“如何治理 Agent 的身份、权限与安全边界”。他认为,未来企业将拥有远多于人的 Agent 数量,而真正的竞争力在于率先完成面向 Agent 的组织与基础设施改造。

8 分钟