Cloudflare 重新设计 Pingora Backend Router(PBR)服务中部分请求分配算法后,在其全球网络范围内释放了超过 100 TB 的 RAM。此次改进结合了哈希点表示压缩、基于统计分析减少哈希点数量,以及保持缓存和到源服务器流量稳定的渐进式迁移。
请求分配中的问题
Cloudflare 使用 pingora-ketama 库实现一致性哈希,这种方法有助于尽可能将可缓存请求导向同一台服务器。这样,数据中心内只需保留文件的一个副本,并为访问该文件提供稳定路径。
但是,为每台服务器使用一个哈希点,可能导致服务器在哈希环上拥有的区间大小存在较大差异,从而造成工作负载不均。因此,Pingora 为每台服务器使用大量虚拟哈希点,并根据存储容量关联权重;此外,还会针对不同的属性和约束创建独立的哈希环。这些哈希环的累积,在某些情况下使每个进程的内存消耗达到 6 GB。
改进数据表示并减少哈希点
环中的每个点由一个 32 位哈希值和一个指向服务器的 32 位索引组成,因此在内存中占用 8 个字节。Cloudflare 团队认为,实际上索引不需要超过 16 位,因为该服务不会同时协调超过约 65,000 台服务器。
仅缩小索引类型并不足够,因为 Rust 的对齐规则会使该结构仍然占用 8 个字节。因此,Cloudflare 将该值和索引存储在一个 6 字节的原始数组中,并通过函数访问二者。这一改动将哈希相关的内存消耗降低了 25%。
更大的收益来自对哈希点数量的重新审查。该服务此前使用每台服务器 160 个点的基础值,并乘以与服务器存储容量相关的权重。分析显示,哈希点数量大幅增加只能带来递减的误差边际改善;在 Cloudflare 讨论的示例中,最后增加的 90,000 个哈希点仅使误差降低约 0.7%。
此外,使用 32 位哈希值会使碰撞在点数增加时变得更加可能,这可能给分布带来不可预期的误差。根据计算和模拟结果,Cloudflare 将每台服务器的哈希点数量减少了 90%,而没有造成明显的误差增加,这也促成了最终的节省。
实际会发生什么变化?
在整个网络范围内一次性切换哈希环并不安全,因为这会重新分配请求,实际上导致缓存有效性大幅下降,并可能增加前往源服务器的流量。因此,PBR 暂时将旧环和新环同时保留在内存中,并为每个请求选择其中一个,从而提供了明确的回滚路径。
迁移分阶段执行,先从小型验证站点开始,然后扩展到更大的数据中心。此外,使用新环的请求比例控制与允许参与的数据中心选择相互分离。Cloudflare 在移除旧路径之前,监控了服务器选择、哈希环版本、连接错误、内存消耗、启动时间、缓存行为以及到源服务器的流量等影响。
工程意义
这一实践表明,在包含数千台服务器的网络中应用时,选择数据结构中字段的大小或确定合适的哈希点数量等低层级优化,其影响可能被成倍放大。同时,这一结果并不意味着在所有系统中减少内存都是安全的;分布准确性、碰撞概率、服务器权重、功能约束以及迁移实施方式,都是需要在更改前进行测量的因素。
相关修改已通过目前未公开的 Cargo 功能在 pingora-ketama 软件包中提供。v2 版本支持压缩存储格式、更快的排序方法以及调整哈希点基础数量的能力,同时保留 v1 版本,并支持同时运行两个哈希环以及在请求级别做出决策。