
Uber 引入了标准化计算单元(Normalized Compute Units,NCU)",以便在高度异构的服务器集群中更一致地分配 CPU。这种方法已应用于 Uber 的有状态编排平台 Odin",它会考虑处理器之间的性能差异,而不是将每个 CPU 核心都视为具有相同性能。
Odin 管理着约 500 万个 CPU 核心,分布在本地数据中心和公有云中,其中包括多个世代的 x86 硬件和 ARM 处理器。Uber 发现,最快与最慢 CPU 核心的单线程性能可能相差近一倍。因此,同一工作负载在不同服务器上运行时,所需的物理 CPU 核心数量可能存在显著差异。
这一问题带来了两种相互冲突的风险。如果按照最慢硬件的性能分配资源,就会浪费较快服务器上的计算能力;如果按照平均使用量分配资源,那么工作负载迁移到较慢服务器时,又可能出现资源不足。对于有状态工作负载而言,由于通常无法简单地将流量迁移到另一台机器,后一种情况可能演变为可靠性问题。
Uber 的解决方案,是将工作负载所需的计算性能与提供这些性能的物理 CPU 核心数量分离。
Odin 会为每种服务器类型分配一个性能系数,并将较老一代服务器的基准值设为 100。新硬件的数值可能高得多;Uber 表示,部分服务器的性能系数接近 190。这些系数最初在硬件准入测试期间确定,随后再根据生产工作负载数据进行调整。
系统会使用这些性能系数,将 CPU 使用量转换为标准化单位。这样,Odin 就可以确定某项工作负载需要多少计算能力,再根据承载该工作负载的服务器,将这一需求换算成不同数量的物理 CPU 核心。
因此,同一项工作负载在性能较快的硬件上可能获得较少的 CPU 核心,在性能较慢的硬件上则会获得更多核心。其目标不是让核心数量保持一致,而是让实际计算能力更加接近。
Uber 还发现,不同技术栈对应的性能系数也有所不同。例如,在 Kafka 测试中,ARM、较老的本地硬件和较新的 x86 系统之间存在显著的性能差异。因此,该公司会使用生产环境中的测量数据更新性能系数,而不是只依赖合成基准测试。
对于无状态服务,服务器之间的性能差异通常可以通过负载均衡解决。流量可以被引导至负载较低或速度更快的机器。
有状态系统则没有同样的灵活性。请求可能必须到达保存特定分片或数据的服务器,将请求转移到其他位置并不能解决底层资源问题。
Uber 在文章中介绍了一些工作负载,其中 Leader 消耗的 CPU 是 Follower 的十倍以上。如果 Leader 从一台高性能服务器迁移到较慢的服务器,即使工作负载本身没有变化,其 CPU 使用率也可能大幅上升,进而造成资源压力。
Uber 已将该方案应用于 Odin 自动扩缩容工作负载中的约 140 万个 CPU 核心。对于 Kafka",不同服务器类型之间的 CPU 利用率最初相差约 8 个百分点,利用率最高的硬件比最低的硬件高出约 50%。
引入性能感知资源分配后,这一差距缩小至约 3 个百分点,利用率最高的硬件只比最低的高约 10%。Uber 还将 Kafka 的 CPU 总分配量减少了约 8%,其中大部分缩减发生在性能更快的硬件上,因此这些节省可能更有价值。
这种方法不同于 Kubernetes 使用的 CPU 抽象"。在 Kubernetes 中,CPU 请求以核心或毫核表示。无论底层机器的规格如何,Kubernetes 都有意将一个 CPU 单位视为绝对数量的 CPU 时间。这种抽象很适合定义可移植的工作负载,但它本身无法表达不同代际处理器之间的相对性能。
Uber 的 NCU 模型解决的是一个略有不同的问题:让资源本身具备性能感知能力。它关注的重点不只是应该在一台机器上放置多少工作负载,或者为某项工作负载分配多少 CPU,而是一次 CPU 分配实际代表了多少计算能力。
原文链接:https://www.infoq.com/news/2026/10/uber-cpu-stateful-workloads/"




