GitHub 重新设计了 GitHub Issues 背后的导航架构,通过将更多工作迁移到客户端,降低了开发者感知到的延迟。工程团队引入了客户端缓存、预测性预取以及基于 Service Worker 的请求处理机制,提升了导航性能,使即时导航体验的比例从 4% 增加到了 22%。这些改动解决了大型 Web 应用中的一个常见挑战:减少由重复网络请求和客户端初始化导致的延迟,尤其是在频繁重复的工作流程中。
这项工作主要针对 GitHub Issues 用户展开,他们经常需要在 Issue、列表以及相关视图之间切换。过去已经获取的信息,现在可以被重新利用,而无需再次从后端服务获取。为了减少这些重复的网络依赖,GitHub 采用了一种本地优先的方法:浏览器会立即使用已有数据进行渲染,同时后台进程会在需要时获取更新的信息。该架构使用了多个客户端存储层,包括用于持久化存储的 IndexedDB,以及用于活跃会话期间高频访问数据的内存缓存。

GitHub Issues 客户端架构
当数据图规模较小且以读取为主(例如 Issues)时,预取能够发挥作用。大多数应用拥有更大的数据图,并且存在读写冲突,因此预取的视图在进入页面后可能仍然需要重新获取数据。可复用的模式是“优先渲染页面外壳 + 基于缓存命中进行数据填充”,而不是预取本身。
从关注 p99 尾部延迟转向关注整体分布质量,是工程成熟度真正体现的地方。
缓存模型采用了 stale-while-revalidate(过期后重新验证)策略。当用户重新访问之前打开过的内容时,应用可以直接展示本地存储的数据,而无需等待服务器响应。随后,系统会在后台执行同步,更新缓存信息,并保持与后端数据的一致性。
GitHub 引入了预热(preheating)机制,以提升缓存效果。该机制会根据用户的导航模式,在用户发起请求之前提前准备可能需要的数据,并填充相关缓存条目。团队还进一步扩展了这一方案,引入了能够拦截浏览器请求并检查本地可用资源的 Service Worker。缓存数据可以立即渲染,同时后台更新会同步更新后的信息。对于不可用或已经过期的数据,请求仍会继续走正常的后端路径。

Service Worker 请求流程
该架构需要在响应速度和数据新鲜度之间取得平衡。GitHub 不再等待每次交互都必须先获取最新服务器状态再进行渲染,而是允许部分内容立即展示,并通过异步方式完成更新。这种方式降低了用户等待时间,同时保留了与后端系统的数据同步能力。
GitHub 高级软件工程师
延迟不仅仅是一个指标。它是一种上下文切换。
GitHub 对导航延迟分布进行了测量。P10 延迟从大约 600 毫秒降低到了 70 毫秒,P25 从 800 毫秒降低到了 120 毫秒,中位延迟则从 1,200 毫秒降低到了 700 毫秒。P75 和 P90 延迟也有所改善,分别从 1,800 毫秒降低到了 1,400 毫秒,以及从 2,400 毫秒降低到了 2,100 毫秒。