本文是对 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 和 OCI
- AmpereOne 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 cause:
multi-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 和 GC
Uber 早期迁移的一批 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 小会影响 Go?
Go 服务经常有大量对象分配、堆扫描和 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 Altra | AmpereOne M |
|---|---|---|
| Processor | Altra | AmpereOne M |
| Cores | 32–128 | 96 cores for OCI FlexSKU,chip 最高可到 192 cores |
| Clock Speed | 最高 3.0 GHz | 96-core model 最高 3.6 GHz |
| L2 Cache / Core | 1 MB | 2 MB |
| System Cache | 16 / 32 MB | 64 MB |
| Memory | 8 通道 DDR4-3200,最高 4 TB | 12 通道 DDR5-5600,最高 1.5 TB |
| PCIe | 最高 128 条 Gen4 lanes | 96 条 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 Cache
System cache 从 16 / 32MB 增加到 64MB。
更大的 system cache 对共享数据、跨核心访问和整体内存压力都有潜在收益。
5. 内存
Ampere Altra 使用 8 通道 DDR4-3200。
AmpereOne M 使用 12 通道 DDR5-5600。
这意味着更高内存带宽。
对 Go GC、存储系统、缓存密集型服务和高并发后端服务来说,内存子系统往往是关键瓶颈之一。
6. PCIe
PCIe 从 Gen4 到 Gen5。
虽然 lanes 数量从最高 128 Gen4 到 96 Gen5,但 Gen5 单 lane 带宽更高。
这对本地 NVMe、网络设备、存储和 I/O 密集型场景很重要。
十、A4 不是单一规格,而是围绕 workload 做组合
原文提到,Uber、OCI 和 Ampere 探索了多种组合:
高频 Flex SKUs:3.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 GC
Go 和 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 本地性 容量利用率 成本对这类 workload,Uber 选择:
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 speed,A1 固定 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/Core:1MB -> 2MB System Cache:16/32MB -> 64MB Memory:8 通道 DDR4-3200 -> 12 通道 DDR5-5600这不是纸面参数,而是直接影响服务性能。
尤其对 Go 和 Java 这类 managed runtime,GC、对象布局和内存访问模式都会受缓存和 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 CPU,Uber 不再必须依赖多 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