AMD Zen 5 架构在服务器与桌面市场的广泛部署,使得缓存拓扑感知调度成为数据库与缓存类应用性能调优的关键战场。Zen 5 延续 Chiplet 设计理念,将核心分组为 CCD(Core Complex Die),每个 CCD 配备独立的 L3 缓存,多个 CCD 通过 Infinity Fabric 互联。当线程在不同 CCD 间迁移时,跨 CCD 的缓存访问会引入显著的延迟开销。Linux 内核即将引入的 Cache Aware Scheduling 功能,正是为了在此硬件拓扑上实现更智能的线程调度。
Zen 5 拓扑结构解析
在制定调度策略前,必须理解 Zen 5 的三级缓存层次结构。每个 CCD 内部包含一个或多个 CCX(Core Complex),每个 CCX 拥有独立的 L3 缓存。以典型的双 CCD Zen 5 处理器为例,CCD0 和 CCD1 各自拥有 32MB L3 缓存,通过 Infinity Fabric 连接。当 PostgreSQL 的 worker 进程在 CCD0 上分配了内存缓冲区,随后被调度到 CCD1 执行时,内存访问将跨越 Fabric 链路,延迟从本地 L3 的约 40 周期增加到跨 CCD 的 120 周期以上。
识别拓扑结构是配置亲和性的第一步。通过 lscpu -e 可以查看 CPU 核心与 NUMA 节点的映射关系,而 /proc/cpuinfo 中的 physical id 字段标识了 CCD 边界。对于 Zen 5 系统,通常每个 CCD 对应一个 NUMA 节点,这为使用 numactl 进行内存与 CPU 绑定提供了便利。
Cache Aware Scheduling 内核机制
Cache Aware Scheduling 的核心思想是在调度决策中引入缓存距离因子。传统 CFS(Completely Fair Scheduler)主要关注负载均衡与公平性,而缓存感知调度会优先将线程放置在与其最近使用的缓存域内。根据 Phoronix 的测试数据,该功能在 PostgreSQL 与 Valkey 工作负载上展现出显著的性能收益。
对于尚未升级到支持 Cache Aware Scheduling 内核的系统,可以通过手动配置线程亲和性获得类似效果。关键在于将数据库工作线程绑定到同一 CCD 的核心集合,确保共享数据结构(如 PostgreSQL 的共享缓冲区、Valkey 的对象存储)驻留在本地 L3 缓存中。
PostgreSQL 线程亲和性配置
PostgreSQL 的性能高度依赖共享内存区的访问效率。在 Zen 5 系统上,推荐采用以下配置策略:
识别 CCD 边界:首先确定每个 CCD 包含哪些逻辑 CPU。以 16 核 32 线程的 Zen 5 处理器为例,假设 CCD0 包含 CPU 0-15,CCD1 包含 CPU 16-31。
绑定 postmaster 与 worker 进程:使用 taskset 或 numactl 将 PostgreSQL 进程限制在单一 CCD。例如:
numactl --cpunodebind=0 --membind=0 postgres -D /var/lib/postgresql/data
此命令将 PostgreSQL 绑定到 NUMA 节点 0(对应 CCD0),同时确保内存分配也在本地节点进行。
配置参数优化:在 postgresql.conf 中,根据 CCD 核心数调整以下参数:
max_worker_processes:设置为 CCD 物理核心数减 1,为系统保留一个核心max_parallel_workers_per_gather:不超过 CCD 核心数的一半,避免并行查询过度占用缓存max_parallel_workers:与max_worker_processes保持一致
连接池亲和性:如果使用 PgBouncer 或类似连接池,建议将连接池进程与数据库进程绑定到同一 CCD,避免连接管理开销跨越 Fabric 链路。
Valkey 缓存调度策略
Valkey 作为高性能键值存储,其单线程事件循环模型与多线程 IO 架构对缓存局部性有不同要求。
主线程绑定:Valkey 的主事件循环线程应绑定到特定 CCD 的单个核心,避免在核心间迁移导致的缓存失效:
taskset -c 0 valkey-server /etc/valkey/valkey.conf
IO 线程配置:当启用 IO 线程(io-threads 配置)时,将这些线程绑定到与主线程同一 CCD 的其他核心。例如,主线程在 CPU 0,IO 线程分配到 CPU 1-3:
io-threads 4
启动脚本中使用 taskset -c 0-3 确保所有线程在同一 CCD 内运行。
内存分配策略:设置 vm.zone_reclaim_mode=1 鼓励内核在本地 NUMA 节点回收内存,减少跨节点分配。同时,考虑使用 madvise 或 numactl --preferred 提示 Valkey 的内存分配行为。
监控与验证
配置完成后,需要通过监控验证调度策略的有效性:
缓存命中率监控:使用 perf stat -e L1-dcache-load-misses,L1-dcache-loads,L3-cache-misses 对比绑定前后的缓存未命中率。理想的配置应使 L3 未命中率显著下降。
调度迁移统计:通过 /proc/<pid>/sched 查看 nr_migrations 字段,验证线程迁移次数是否降低。
性能基准测试:使用 Valkey 自带的 valkey-benchmark 进行压测,对比绑定前后的吞吐量与延迟 P99 指标。根据测试数据,合理的线程绑定可使吞吐量提升 8-15%,尾部延迟降低 20% 以上。
风险与注意事项
缓存感知调度并非万能方案。过度绑定可能导致负载不均,当系统运行多种工作负载时,独占 CCD 可能造成资源浪费。建议在以下场景谨慎使用:
- 多租户环境:不同租户的工作负载可能竞争同一 CCD 资源
- 混合读写负载:读密集与写密集进程可能需要不同的缓存策略
- 动态扩缩容:云环境中的弹性实例可能跨越 CCD 边界
此外,Cache Aware Scheduling 作为内核新特性,在生产环境部署前应在测试集群充分验证,关注与现有调度器特性的兼容性。
资料来源
- Phoronix: Cache Aware Scheduling Shows Nice Wins For AMD Zen 5 On PostgreSQL, Valkey, Network Performance
- SUSE Documentation: Optimizing Linux for AMD EPYC 9005 Series Processors
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。