从软件到硅片:Uber、OCI 与 Ampere 如何联合优化 AmpereOne M A4 计算实例
本文是对 How Uber, OCI™, and Ampere® Co-Optimized OCI AmpereOne® M A4 Compute 的整理与翻译。内容结构概览本文围绕 Uber、Oracle Cloud Infrastructure 和 Ampere 如何共同优化 OCI AmpereOne M A4 Compute 展开主要包括Uber 为什么开始从本地数据中心迁移到云上并引入 Arm 架构为什么这不是简单“换 CPU”而是从软件负载到芯片设计的协同优化OCI Ampere A1 / A2 在 Uber Arm 化过程中的作用Uber 在早期 Arm 迁移中遇到的关键性能问题为什么双路服务器会影响延迟敏感型 Java 和 Go 服务Go 服务中的 GOMEMLIMIT、TLB、cache、page fault 和 GC 问题为什么部分服务不能只靠横向扩容解决性能问题Gurobi 这类单线程敏感工作负载为什么需要更高单核频率Ampere Altra 固定 3.0GHz 频率和无 turbo 机制带来的资源闲置问题Uber 如何把真实生产负载反馈给 Ampere 和 OCIAmpereOne M 相比 Ampere Altra 的关键规格变化A4 实例如何在频率、核心数、内存、PCIe、本地 NVMe 和远程块存储之间做取舍为什么 Uber 把工作负载分成“延迟敏感无状态服务”和“吞吐导向存储系统”这次合作的本质从适配已有硬件到影响下一代云计算基础设施设计对后端、云基础设施、容量规划和硬件选型的启发一、这篇文章讲的不是“Uber 换了云服务器”表面看原文是在介绍 OCI AmpereOne M A4 Compute。但真正有意思的地方不只是一个新实例规格而是 Uber、OCI 和 Ampere 三方如何把真实生产负载反馈到下一代云硬件设计中。很多公司上云时通常是这样云厂商提供实例规格 用户根据规格选择机器 业务迁移上去 发现性能问题后调参数、扩容、换机型Uber 这篇文章讲的是另一个层次Uber 迁移大规模真实负载 发现 Arm 实例在生产环境中的性能瓶颈 将 workload 特征反馈给 OCI 和 Ampere OCI 和 Ampere 根据这些反馈调整实例和芯片设计 最终形成更贴近 Uber 真实负载的 A4 Compute这背后的思想很重要基础设施优化不再停留在“软件适配硬件”而是让真实软件负载反过来影响硬件和云实例设计。这就是原文所谓 “software meets hardware”。二、背景Uber 从本地数据中心走向多云和 Arm 架构原文提到Uber 在 2023 年 2 月开始从本地数据中心迁移到云上使用 OCI 和 Google Cloud Platform。在这个过程中Uber 同时面临两个巨大挑战大规模 workload 从本地数据中心迁移到云 在原本以 x86 为主的环境中引入 Arm-powered compute instances这不是小规模试点。Uber 的基础设施承载着数千个微服务 大量存储数据库 复杂的多语言服务栈 高吞吐在线服务 延迟敏感业务路径 成本敏感型计算任务过去这些系统主要运行在 x86 环境里。引入 Arm 意味着整个基础设施体系都要变成 multi-architecture。这会影响构建系统 镜像发布 依赖库 运行时 性能调优 容量规划 故障排查 服务迁移 硬件选型所以 Uber 上 Arm 不是简单“把容器换到 Arm 机器上跑”。它是一次从 build、deploy、runtime 到 capacity management 的系统性迁移。三、为什么 Uber 要引入 Arm从原文看OCI 采用 Ampere Arm-based processors 的核心动机包括更高 performance per watt 更低 energy consumption 更高 compute density 更好的云效率对云厂商来说这些意味着单位机架、单位电力、单位散热下能提供更多计算能力。对 Uber 这种大规模云客户来说这意味着更好的价格性能比、更低能耗以及更灵活的硬件供应选择。Uber 还特别提到采用 OCI 和 Ampere 带来了两个优势energy efficiency hardware diversityenergy efficiency 很好理解。云上算力规模越大能源效率越重要。hardware diversity 则更像供应链和基础设施韧性的考虑。如果所有 workload 都依赖同一种 CPU 架构、同一种供应链、同一种实例类型长期风险会更集中。多架构环境虽然复杂但也提高了运营灵活性。所以 Uber 引入 Arm既是成本和性能问题也是可持续性、供应链和长期基础设施战略问题。四、A1 / A2 是基础A4 是带着生产经验再设计OCI Ampere A1 和 A2 是 Uber Arm 化的基础。它们帮助 Uber 开始让平台具备 Arm-ready 能力。在这个阶段Uber 采用多阶段方法把原本以 x86 为主的基础设施逐步改造成能支持 Arm 的环境。但 A1 / A2 更像第一阶段。它们让 Uber 发现哪些服务可以直接迁移 哪些服务需要重新编译 哪些服务性能敏感 哪些运行时参数在 Arm 上表现不同 哪些硬件特性会影响真实生产 workload等到 Uber 开始测试生产服务时团队逐渐看清了 Uber 软件代码与 Arm 指令集、缓存层级、TLB、频率、内存带宽、NUMA 拓扑之间的真实关系。这些反馈后来被用于 AmpereOne M silicon 和 OCI A4 instance family 的设计优化。这就是原文的核心线索A1 / A2 帮助 Uber 上 Arm A1 / A2 暴露真实生产问题 这些问题反馈给 OCI 和 Ampere A4 吸收这些经验重新优化五、关键经验一双路系统会影响延迟敏感型负载Uber 最早用 specJBB2015 做 synthetic benchmarking。specJBB2015 是 Java 服务器端 workload 常用 benchmark用来衡量 Java 应用在吞吐和延迟方面的表现。测试中Uber 发现一个重要问题dual socket systems 在 latency-sensitive operation 上表现下降原文里具体提到 critical Java operations per second 下降。Go benchmarks 也显示 operation execution speed 对此敏感。最终Uber、OCI 和 Ampere 一起定位到 root causemulti-socket system 中 cross-socket link bandwidth 会带来性能限制简单解释一下。双路服务器有两个 CPU socket。每个 socket 有自己的核心、缓存、内存访问路径。如果某个 workload 的线程和数据跨 socket 访问就会经过 socket 之间的互联链路。这会带来额外访问延迟 跨 socket 带宽限制 NUMA 复杂性 缓存一致性成本 尾延迟抖动对吞吐型批处理来说这不一定是致命问题。但对低延迟服务尤其是 Java / Go 后端在线服务这类跨 socket 开销会变得很明显。后来Ampere 提供了更高单 socket 核心数。这意味着 Uber 不再一定需要多路服务器来获得高核心数。这就是一个很典型的硬件架构取舍过去为了更多核心上双路 问题跨 socket 通信增加延迟 改进单 socket 提供足够多核心避免跨 socket 开销对大规模在线服务来说这非常关键。因为尾延迟往往比平均吞吐更重要。六、关键经验二Go 服务、GOMEMLIMIT、TLB 和 GCUber 早期迁移的一批 Go 服务出现了 OOM 错误和 GOMEMLIMIT 设置有关。GOMEMLIMIT 是 Go runtime 的一个内存控制参数用来告诉 Go runtime 希望把内存使用控制在某个软限制附近。它会影响 GC 触发策略和内存管理行为。原文说Uber 将 Go performance degradation 主要归因于smaller Translation Lookaside Buffers smaller cache sizes more page faults slower garbage collection这里可以展开一下。1. TLB 是什么TLB全称 Translation Lookaside Buffer。它是 CPU 中用于缓存虚拟地址到物理地址映射的小型高速缓存。程序访问内存时CPU 需要把虚拟地址转换成物理地址。如果 TLB 命中转换很快。如果 TLB miss就要走更慢的页表查询。2. 为什么 TLB 小会影响 GoGo 服务经常有大量对象分配、堆扫描和 GC 行为。如果工作集比较大内存访问分布又比较散TLB miss 增加就会带来更多 page table walk 和 page fault 相关开销。GC 本身也需要扫描对象图。如果缓存和 TLB 行为不好GC 过程会变慢CPU 时间也会更多耗在内存访问上。所以 Go 服务在 Arm 平台上的性能不只是“编译成 arm64 能跑”这么简单。运行时、GC、缓存、TLB、页大小、内存带宽都会影响最终表现。Uber 的反馈让 Ampere 和 OCI 更清楚下一代实例不能只看核心数也要看 cache、TLB、内存子系统和 GC 友好性。七、关键经验三不是所有服务都能靠横向扩容解决云原生架构里经常有一个默认思路性能不够就横向扩容 多加几个实例对很多无状态服务来说这确实有效。但原文指出Uber 的计算平台也有一些非常 latency-sensitive 的服务它们有单线程性能需求不能只靠横向扩容解决。典型例子是使用 Gurobi mixed integer program solver 的服务。这类 solver 依赖很高的单核时钟频率。如果单线程执行速度不够快增加更多实例不一定能解决单个请求的延迟问题。Uber 发现使用 Gurobi 的服务在 OCI A1 上相比原来的本地 x86 服务器表现较慢。原因之一是 A1 上 Ampere Altra CPU 的单核频率固定为 3.0GHz。更重要的是Ampere Altra CPU 不支持 core turbo clocking也就是说如果 workload 只使用部分核心剩余核心闲置时CPU 也不能把活跃核心提升到更高频率。这会导致一种资源闲置很多核心没有被使用 但活跃核心也不能加速 单线程性能仍然受固定频率限制这对单线程敏感型服务不友好。于是Uber 给 OCI 和 Ampere 的反馈就变得非常明确下一代实例需要更好的单核性能尤其是更高频率或针对高单线程性能的规格选项。八、从经验到设计A4 如何吸收这些反馈A1 / A2 暴露的问题最后被用于 OCI Ampere A4 instance family 的设计。原文说Uber Engineering 向 Ampere architects 分享了详细的 workload characteristics 和 performance targets。这些信息帮助 AmpereOne M silicon 的设计和优化也促使 Oracle 和 Ampere 提供基于 Uber 反馈的 FlexSKU 选项用于追求最高单线程性能的 CPU。这里的关键词是workload characteristics performance targets FlexSKUworkload characteristics 指真实生产负载特征。比如哪些服务延迟敏感 哪些服务吞吐敏感 哪些服务需要高单核频率 哪些服务需要更大缓存 哪些服务需要更多内存带宽 哪些服务适合 VM 哪些服务需要本地 NVMeperformance targets 则是这些 workload 需要达到的性能目标。FlexSKU 可以理解成更灵活的 CPU / instance 规格选项。比如更高频率、特定核心数、特定内存比等组合。这就是三方合作的本质Uber 提供真实 workload 和性能目标 Ampere 调整芯片能力 OCI 调整实例配置和云产品形态九、Ampere Altra 和 AmpereOne M 的规格对比原文给了一个规格表整理如下特性Ampere AltraAmpereOne MProcessorAltraAmpereOne MCores32–12896 cores for OCI FlexSKUchip 最高可到 192 coresClock Speed最高 3.0 GHz96-core model 最高 3.6 GHzL2 Cache / Core1 MB2 MBSystem Cache16 / 32 MB64 MBMemory8 通道 DDR4-3200最高 4 TB12 通道 DDR5-5600最高 1.5 TBPCIe最高 128 条 Gen4 lanes96 条 Gen5 lanes这张表很值得细看。1. 核心数AmpereOne M 在芯片层面最高可到 192 cores。OCI FlexSKU 使用 96-core 规格。对 Uber 来说这意味着可以在单 socket 上获得很高核心数从而减少双路服务器带来的 cross-socket latency 问题。2. 频率Ampere Altra 最高 3.0GHz。AmpereOne M 96-core model 最高 3.6GHz。这直接回应了 Uber 对单线程性能的需求。尤其是 Gurobi 这类服务不能只靠横向扩容解决高频核心很重要。3. L2 Cache每核心 L2 cache 从 1MB 增加到 2MB。这对很多服务都有帮助。更大的 L2 cache 可以减少对更慢内存层级的访问改善延迟敏感型服务和运行时行为。4. System CacheSystem cache 从 16 / 32MB 增加到 64MB。更大的 system cache 对共享数据、跨核心访问和整体内存压力都有潜在收益。5. 内存Ampere Altra 使用 8 通道 DDR4-3200。AmpereOne M 使用 12 通道 DDR5-5600。这意味着更高内存带宽。对 Go GC、存储系统、缓存密集型服务和高并发后端服务来说内存子系统往往是关键瓶颈之一。6. PCIePCIe 从 Gen4 到 Gen5。虽然 lanes 数量从最高 128 Gen4 到 96 Gen5但 Gen5 单 lane 带宽更高。这对本地 NVMe、网络设备、存储和 I/O 密集型场景很重要。十、A4 不是单一规格而是围绕 workload 做组合原文提到Uber、OCI 和 Ampere 探索了多种组合高频 Flex SKUs3.6GHz vs 3.2GHz bare-metal 和 VM deployments 92 到 192 cores 基于 12-channel DDR5 的多种 core-to-memory ratios local NVMe vs remote block storage这说明 A4 的设计不是单纯“核心越多越好”。真正的云实例优化要在多个维度之间做取舍核心数 单核频率 缓存大小 内存带宽 内存容量 虚拟化形态 NUMA 和 I/O 复杂度 本地盘 远程块存储 成本 迁移复杂度不同 workload 需要不同组合。比如低延迟无状态服务需要高单核性能和稳定 GC 存储系统需要并行度、内存效率和 I/O 能力 部分服务需要本地 NVMe 部分服务用远程块存储就够所以 A4 优化的关键不是推出一个万能机型而是根据 Uber 真实 workload 分层设计。十一、工作负载分类一延迟敏感无状态服务Uber 和 OCI / Ampere 最终把负载大致分成两类。第一类是 latency-sensitive stateless services。这类服务的特点是在线请求路径 用户体验敏感 尾延迟重要 通常可水平扩展 但每个请求仍然受单实例性能影响 GC 抖动会影响延迟 迁移复杂度要低对这类服务Uber 优先考虑per-core performance predictable garbage collection higher CPU frequency about 8 GB per vCore VM deployment这里有几个细节。1. Per-core performance服务延迟经常取决于单个请求能多快被执行。即使服务可以横向扩容单请求路径仍然需要高 per-core performance。2. Predictable GCGo 和 Java 服务都可能受到 GC 抖动影响。缓存、TLB、内存带宽、CPU 频率都会影响 GC 行为。Uber 希望实例提供更可预测的 GC而不是在压力下出现长尾抖动。3. Higher CPU frequency对延迟敏感服务高频核心能直接改善请求处理时间。4. About 8GB per vCore这体现了 memory-to-core ratio 的规划。如果每核内存太少服务容易受内存压力影响。如果每核内存太多又会造成资源浪费。5. VM deployment原文提到选择 VM deployment是为了避免 NUMA / I/O tuning并让从上一代实例迁移更简单。这点很实际。裸金属性能可能更可控但也可能要求更多底层调优。如果大规模迁移需要尽量降低复杂度VM 是更现实的选择。十二、工作负载分类二吞吐导向存储系统第二类是 throughput-oriented storage systems。这类系统关注的不是单个请求的极致低延迟而是整体吞吐、资源利用率和容量效率。它们通常关心并行度 内存效率 工作集大小 存储 I/O 本地性 容量利用率 成本对这类 workloadUber 选择parallelism memory efficiency at efficient clocks flexible memory-to-core ratios align observed working-set sizes avoid over-provisioning storage sized to workload locality local NVMe when it matters remote block when it doesn’t展开说就是1. 并行度存储系统通常能利用更多核心处理并发请求、后台 compaction、replication、flush、query 等任务。所以高核心数有价值。2. 内存效率存储系统经常有较大 working set。内存太少会影响缓存命中、读放大和延迟。内存太多又会造成浪费。所以需要更灵活的 memory-to-core ratio。3. 不过度配置如果某个 workload 只需要 300GB 内存却被迫使用 1TB 内存实例就会浪费。如果实例规格能更贴合 working-set size整体 packing efficiency 会更好。4. 本地 NVMe 与远程块存储不是所有存储 workload 都需要本地 NVMe。有些 workload 对本地低延迟 I/O 敏感就应该使用 local NVMe。有些 workload 的存储访问模式对本地性没那么敏感remote block storage 就足够。这就是 “storage sized to workload locality”。核心思路是不要为了少数需要本地盘的场景让所有 workload 都配置昂贵本地存储。十三、为什么这次合作很特别普通云实例设计往往是云厂商和芯片厂商决定产品形态客户根据实例规格选择。这次合作更像反过来Uber 在生产环境中大规模运行真实 workload Uber 发现 Arm 实例上的真实瓶颈 Uber 提供 workload 特征和性能目标 Ampere 将这些反馈用于下一代 silicon OCI 将这些反馈用于 instance configuration 三方共同优化 A4 Compute这说明 Uber 已经不只是云资源消费者而是基础设施 co-design 的参与者。原文结论里有一句很关键Uber Engineering has evolved from adapting to existing hardware to influencing the next generation of compute optimized for our real workloads.翻译一下就是Uber 工程团队已经从适配已有硬件演进到影响下一代面向真实负载优化的计算平台。这是这篇文章最重要的信号。十四、这篇文章背后的基础设施理念按消费方式设计而不是按供给方式设计原文开头说Uber 希望围绕“实际如何消费计算资源”来塑造基础设施而不是只围绕“如何 provision 计算资源”。这句话挺有意思。传统容量规划可能更像我需要多少 vCPU 我需要多少内存 我需要多少磁盘 我需要什么实例规格但 Uber 想看的更细这个 workload 对单核性能敏感吗 它的 GC 行为如何 它的 TLB miss 多吗 它的 working set 多大 它受 cross-socket latency 影响吗 它需要本地 NVMe 还是远程块存储 它是吞吐导向还是尾延迟导向 它是否能从高核心数获益 它是否因为固定频率而浪费核心这就是从 resource provisioning 走向 workload-aware infrastructure。云资源不应该只是“买多少核、多少内存”。它应该根据 workload 的真实运行特征来设计和分配。十五、为什么这对后端工程师也重要这篇文章虽然讲硬件和云实例但对后端工程师非常有启发。很多后端性能问题最后并不是单纯代码问题。比如Go 服务 GC 变慢 Java 服务尾延迟变差 存储服务吞吐上不去 某些服务横向扩容也解决不了单请求延迟 服务明明 CPU 没打满但性能就是不好这些问题可能和硬件有关CPU 频率 缓存大小 TLB 内存带宽 NUMA 跨 socket 访问 本地盘和远程盘 PCIe 带宽 虚拟化开销如果后端工程师完全不了解这些就很容易只在应用层瞎调参数。比如看到 Go 服务 OOM 或 GC 慢只调 GOMEMLIMIT。看到服务延迟高只加实例。看到存储服务吞吐低只加 CPU。但真正瓶颈可能在 TLB、cache、memory bandwidth 或 cross-socket link。所以这篇文章提醒我们软件性能优化最终会遇到硬件边界。理解硬件不是底层工程师的专属技能大规模后端服务同样需要。十六、为什么 Arm 迁移不是“重新编译一下”很多人会把 Arm 迁移想得太简单把镜像编成 arm64 跑一下测试 没问题就上线但 Uber 的经历说明真正的 Arm 迁移至少有几个层面。1. 构建和发布多架构镜像、多架构依赖、多架构 CI/CD、构建缓存、二进制分发都要调整。2. 运行时行为同一段 Go 或 Java 代码在不同 CPU 架构、缓存层级、TLB 和内存系统上运行时表现可能不同。3. 性能模型x86 上的性能经验不能直接套到 Arm。比如 turbo、频率、cache、NUMA、memory bandwidth 都不同。4. 容量规划同样 vCPU 数不代表同样性能。需要重新建立 Arm 实例上的 capacity model。5. 工作负载筛选不是所有服务都适合第一批迁移。有些服务很容易迁移有些服务需要硬件规格更成熟后再迁移。6. 供应链和基础设施策略大规模引入 Arm 会影响硬件采购、云资源组合、故障域、成本模型和长期平台路线。所以 Arm 迁移是一项系统工程。十七、单 socket 高核心数为什么有价值原文特别强调Ampere 提供的 high core counts per socket 让 Uber 不再需要多 socket servers。这个点值得单独说。多 socket 服务器的问题不是不能用而是会增加复杂性NUMA 调度 跨 socket 内存访问 跨 socket cache coherency 线程绑定 I/O locality 延迟抖动 带宽瓶颈如果一个 CPU socket 就能提供足够多核心系统会简单很多。对云平台来说单 socket 高核心数也有好处减少跨 socket 延迟 简化实例性能模型 提高延迟可预测性 降低 NUMA tuning 需求 更适合大规模通用 workload尤其对 Uber 这种有大量 Go / Java 微服务的场景减少跨 socket 复杂性非常有价值。十八、频率为什么仍然重要云原生时代经常强调并发和横向扩展但频率仍然很重要。原因很简单不是所有任务都能无限并行。比如单个请求的关键路径 串行计算逻辑 solver 类计算 锁保护的临界区 某些 GC 或 runtime 操作 延迟敏感的协议处理如果这些部分受单线程性能限制更多核心不一定能解决。原文中 Gurobi mixed integer program solver 就是例子。它依赖最高 clock speedA1 固定 3.0GHz 且没有 turbo就导致部分资源闲置时也不能提升单核性能。AmpereOne M 96-core model 最高 3.6GHz正是对这一问题的回应。这说明在实例选型时不能只看核心数多不多 总吞吐高不高还要看单核性能够不够 频率是否适合延迟敏感 workload 低利用率时是否能提升活跃核心性能十九、缓存和内存子系统为什么影响云服务很多后端服务看起来是 CPU-bound但深入看可能是 memory-bound。例如对象频繁分配 hash map 访问 序列化 / 反序列化 GC 扫描 缓存查找 数据库内存结构 存储引擎索引 大规模并发请求状态这些场景会频繁访问内存。如果 cache 不够TLB miss 多内存带宽不足CPU 核心可能就在等数据。AmpereOne M 相比 Ampere Altra 的几个变化正是围绕这一点L2 Cache/Core1MB - 2MB System Cache16/32MB - 64MB Memory8 通道 DDR4-3200 - 12 通道 DDR5-5600这不是纸面参数而是直接影响服务性能。尤其对 Go 和 Java 这类 managed runtimeGC、对象布局和内存访问模式都会受缓存和 TLB 影响。二十、VM 和裸金属怎么选原文提到Uber 探索了 bare-metal 和 virtual-machine deployments。最后对于延迟敏感无状态服务原文倾向于 VM deployment原因是避免 NUMA / I/O tuning 从上一代实例迁移更简单这点很工程化。很多时候裸金属听起来性能更好但它也意味着更多底层细节暴露给用户。比如NUMA 绑定 I/O 亲和性 驱动调优 实例生命周期 迁移复杂度 故障恢复流程对大规模迁移来说少一点极限性能换来更低迁移复杂度和更稳定运营可能是更划算的。这也是云基础设施里常见取舍极致性能 运营复杂度 迁移成本 调优成本 长期维护成本Uber 没有一味追求 bare metal而是按 workload 选择。二十一、本地 NVMe 和远程块存储怎么选原文也提到 local NVMe versus remote block storage。这同样不是简单“本地 NVMe 更快所以都用本地 NVMe”。本地 NVMe 的优势是低延迟 高吞吐 适合强本地性 workload 适合写入密集型存储系统但它也可能带来容量固定 迁移复杂 故障恢复复杂 资源容易 stranded 成本更高远程块存储的优势是容量灵活 易于扩展 更适合不依赖强本地性的 workload 运维模型更简单所以原文说local NVMe when it matters remote block when it doesn’t这句话非常实用。不要把高规格资源平均分给所有 workload。应该根据 workload locality 决定存储类型。二十二、这篇文章里的“协同优化”到底是什么Co-optimization 不是三方一起开会说“我们要更快”。它至少包含几个层面。1. Workload 层Uber 提供真实生产 workload 的行为数据和性能目标。包括延迟、吞吐、GC、内存、单线程性能、存储 I/O 等。2. Silicon 层Ampere 根据这些反馈优化下一代 AmpereOne M silicon。比如更高频率、更大 L2 cache、更大 system cache、更高内存带宽等。3. Cloud instance 层OCI 根据这些 silicon 能力和 Uber 需求设计 A4 instance family。比如 FlexSKU、core count、memory ratio、VM / bare metal、本地盘 / 远程盘选择等。4. Platform migration 层Uber 再把这些实例映射回自己的 workload 分类和迁移计划。比如哪些服务优先迁移到高频 VM哪些存储系统用不同 memory-to-core ratio。这就是完整闭环生产负载 ↓ 性能问题 ↓ 硬件反馈 ↓ 芯片设计 ↓ 实例配置 ↓ 平台迁移 ↓ 继续观测生产表现二十三、对容量规划的启发大规模基础设施容量规划不能只靠 vCPU 数量。如果只看 vCPU很容易误判。两个 96 vCPU 实例可能完全不同单核频率不同 缓存大小不同 内存带宽不同 NUMA 拓扑不同 本地盘能力不同 虚拟化开销不同 GC 表现不同 尾延迟不同所以更好的容量规划应该按 workload 建模。比如延迟敏感无状态服务关注 p99、GC pause、per-core throughput 吞吐型存储系统关注 IOPS、memory footprint、cache hit、packing efficiency 单线程 solver关注 wall-clock runtime 和单核频率 Go 服务关注 GOMEMLIMIT、GC CPU、page faults、RSS、OOM Java 服务关注 specJBB 类指标、JIT、GC、heap、tail latency这样才能真正选择适合的实例。二十四、对云厂商和硬件厂商的启发这篇文章也说明云实例设计不能只靠标准 benchmark。specJBB2015 这类 benchmark 很有价值但真实生产 workload 更复杂。标准 benchmark 能发现一部分问题。但只有真实业务迁移上来才会看到某些服务对 cross-socket link 敏感 某些 Go 服务受 TLB 和 cache 影响 某些 solver 受固定频率限制 某些存储 workload 需要特定 memory-to-core ratio 某些 workload 对本地 NVMe 有强需求 某些 workload 用远程块存储更省所以云厂商和芯片厂商如果想优化 hyperscale customer 的真实效率就必须深入客户 workload而不是只做通用规格堆料。这也是这篇文章展示的三方合作价值。二十五、我的理解这是“云上实例定制化”的一个方向我觉得这篇文章最核心的变化是云计算正在从通用实例选择走向 workload-aware instance co-design。过去云上选型像买菜单通用型 计算型 内存型 存储型 高性能型用户根据大概分类选择。但 Uber 这种规模的客户会把问题问得更细这类 Go 服务是不是因为 TLB 小导致 GC 慢 这个存储系统真正 working set 是多少 这个 solver 是不是需要 3.6GHz 而不是更多核心 这个服务是不是应该避开多 socket 这个 workload 到底需要 local NVMe 还是 remote block当客户规模足够大云厂商和芯片厂商就有动力根据真实 workload 共同优化实例。这不是每家公司都能做到的。但它代表了云基础设施演进方向从标准化实例 到 workload-aware 实例 再到软件、系统、硅片共同设计二十六、这篇文章和 Uber 其他基础设施文章的关系Uber 最近很多文章都有一个共同主题不是只在软件层调优而是把问题平台化、系统化、自动化。比如Go Zero-Growth Stack用 profile-guided 方法调整 runtime 栈策略 Rate Limiting从 Redis 限流走向服务网格全局限流和自动配置 OpenSearch gRPC从 REST/JSON 适配层走向原生 gRPC OpenSearch Pull-Based Ingestion从 push-based 写入走向流式拉取索引 JUnit Migration用 OpenRewrite Bazel Shepherd 做大规模代码现代化 本文从适配云硬件走向影响云实例和芯片设计它们背后的工程思想一致先用真实生产数据发现瓶颈再把解决方案沉淀到平台层最后让平台能力反过来改变系统边界。这篇文章只是把这个边界推进到了 silicon 和 cloud instance 层。二十七、总结Uber 这篇文章讲述了 Uber、Oracle Cloud Infrastructure 和 Ampere 如何共同优化 OCI AmpereOne M A4 Compute。背景是 Uber 从 2023 年 2 月开始从本地数据中心迁移到云上使用 OCI 和 Google Cloud Platform同时将 Arm-powered compute instances 引入原本以 x86 为主的环境。这一迁移需要支撑数千个微服务和大量存储数据库不只是重新编译镜像而是构建真正的 multi-architecture 基础设施。OCI Ampere A1 和 A2 是 Uber Arm 化的基础。它们帮助 Uber 让平台具备 Arm-ready 能力也让 Uber 在真实生产 workload 中发现了一系列关键问题。第一specJBB2015 和 Go benchmarks 显示dual socket systems 对延迟敏感操作不友好。团队最终定位到 multi-socket system 中 cross-socket link bandwidth 的瓶颈。由于 Ampere 能提供高核心数单 socket CPUUber 不再必须依赖多 socket servers从而减少跨 socket 通信带来的延迟和 NUMA 复杂性。第二Uber 早期一批 Go 服务在 GOMEMLIMIT 设置下出现 OOM 问题。分析发现Go 性能下降主要来自更小的 TLB 和 cache sizes它们导致更多 page faults 和更慢的 garbage collection。这说明 Go 服务在 Arm 上的表现不只取决于能否编译运行还取决于缓存、TLB、内存子系统和 GC 行为。第三Uber 还有一些非常 latency-sensitive 的服务不能只靠横向扩容解决。例如运行 Gurobi mixed integer program solver 的服务依赖高单线程性能。它们在 OCI A1 上相比本地 x86 服务器表现较慢原因之一是 Ampere Altra 固定 3.0GHz 单核频率而且不支持 core turbo clocking。这会导致部分核心空闲时活跃核心也无法提升频率出现资源闲置。这些经验被反馈给 OCI 和 Ampere并影响了 AmpereOne M silicon 和 OCI A4 instance family 的设计。AmpereOne M 相比 Ampere Altra 有多个关键变化核心OCI FlexSKU 为 96 cores芯片最高可到 192 cores 频率96-core model 最高 3.6GHz而 Altra 最高 3.0GHz L2 Cache/Core从 1MB 增加到 2MB System Cache从 16/32MB 增加到 64MB 内存从 8 通道 DDR4-3200 升级到 12 通道 DDR5-5600 PCIe从 Gen4 升级到 Gen5在 A4 设计中Uber、OCI 和 Ampere 探索了高频 FlexSKU、裸金属和 VM、92 到 192 cores、多种 core-to-memory ratios、本地 NVMe 和远程块存储等组合。最终他们围绕两类主要 workload 做取舍。对延迟敏感无状态服务优先考虑 per-core performance、predictable GC、更高 CPU 频率、约 8GB per vCore以及 VM deployment以减少 NUMA / I/O tuning 并简化从上一代实例迁移。对吞吐导向存储系统则优先考虑 parallelism、memory efficiency、灵活 memory-to-core ratio、与 working-set size 对齐的资源配置以及根据数据本地性选择 local NVMe 或 remote block storage避免过度配置和资源闲置。这篇文章的核心不是“OCI A4 更快”这么简单而是说明 Uber 的基础设施创新方式发生了变化。过去Uber 需要适配已有硬件。现在Uber 通过真实生产 workload 和性能目标开始影响下一代云计算实例和芯片设计。对后端和基础设施工程师来说这篇文章最大的启发是大规模性能优化最终会跨越软件、运行时、操作系统、云实例和芯片。只看 vCPU 和内存远远不够真正的容量规划和平台优化必须理解 workload 如何消耗计算资源。在云规模足够大、负载足够复杂的场景下最好的基础设施不是通用堆料而是让软件、系统和硅片围绕真实 workload 共同优化。参考资料How Uber, OCI™, and Ampere® Co-Optimized OCI AmpereOne® M A4 Compute