4. CPU调度与数据库负载
数据库主机的CPU调度问题,往往不是“CPU不够快”,而是“该跑在某个核上的线程被挪走了”。在RHEL上,数据库进程的响应时间同时受三件事影响:进程优先级(nice值与实时优先级)、调度策略(CFS、SCHED_FIFO、SCHED_RR、SCHED_BATCH、SCHED_IDLE)、以及NUMA亲和性(线程与内存是否落在同一节点)。三者叠加,才会出现“CPU利用率不高但SQL延迟抖动”的典型现象。
一、先理解RHEL的调度层次
RHEL默认使用CFS(完全公平调度器),普通进程的优先级由nice值体现,范围-20到19,数值越小优先级越高。数据库进程通常以普通优先级运行,但Oracle的LGWR、DBWn等后台进程,以及MySQL的InnoDB刷盘线程,对延迟敏感,若与大量批处理进程共享CPU,会被CFS按权重分配时间片,导致提交延迟抖动。
实时调度策略SCHED_FIFO和SCHED_RR优先级为1到99,高于所有普通进程。把数据库关键线程设为实时策略,可以避免被普通负载抢占,但风险是:若实时线程进入忙等,会饿死其他进程,甚至触发soft lockup。因此生产上更稳妥的做法是:用cgroup的cpu.weight做权重隔离,用cpuset绑定核,而不是盲目上实时策略。
二、NUMA亲和性:数据库延迟的隐形杀手
在多路服务器上,CPU和内存被划分为多个NUMA节点。跨节点访问内存的延迟通常是本地访问的1.5到2倍。数据库的共享内存、Buffer Pool、Redo Log Buffer若被分散到多个节点,线程在节点A运行却访问节点B的内存,就会产生远端访问。更严重的是,Linux默认的自动NUMA平衡(Auto NUMA)会在运行中迁移任务和内存,虽然提升吞吐,但可能引入不可预测的延迟抖动。
判断是否存在NUMA问题,可以观察numastat中的numa_miss和numa_foreign,以及/proc/<pid>/numa_maps。若某个数据库进程的numa_miss持续增长,说明它频繁访问远端内存。
三、实际调优:从观察到落地
假设一台双路服务器,两个NUMA节点,运行Oracle 19c。观察到AWR报告中log file sync平均等待2ms,但P99达到18ms。检查numastat -p <LGWR_PID>,发现numa_miss为12000,numa_foreign为8000,说明LGWR线程频繁跨节点访问内存。
第一步,确认LGWR所在节点与共享内存分布。使用numactl --hardware查看节点拓扑,用ps -eo pid,psr,comm | grep lgwr查看LGWR当前运行核。若LGWR在Node 1,而SGA主要分配在Node 0,则跨节点访问成立。
第二步,绑定实例到单一节点。对于单实例数据库,推荐将整个实例绑定到一个NUMA节点,避免跨节点内存访问:
numactl --cpunodebind=0 --membind=0 -- /u01/app/oracle/product/19c/dbhome_1/bin/oracle
# 或在启动脚本中设置
export NUMA_BIND="numactl --cpunodebind=0 --membind=0"
$NUMA_BIND $ORACLE_HOME/bin/sqlplus / as sysdba
第三步,隔离批处理负载。将备份、统计信息收集等批处理进程绑定到Node 1,并设置较低优先级:
# 将备份进程绑定到Node 1,nice=19
numactl --cpunodebind=1 --membind=1 nice -n 19 /backup/rman_backup.sh
# 使用cgroup v2限制批处理CPU权重
mkdir -p /sys/fs/cgroup/batch
echo "cpu.weight 10" > /sys/fs/cgroup/batch/cpu.weight
echo $BACKUP_PID > /sys/fs/cgroup/batch/cgroup.procs
第四步,调整关键线程优先级。LGWR、DBWn等线程可适当提高优先级,但不建议直接上实时策略。可通过renice调整:
# 将LGWR的nice值从0调整为-5
renice -n -5 -p $(pgrep -f "ora_lgwr")
# 验证
ps -eo pid,ni,comm | grep lgwr
第五步,关闭Auto NUMA。在数据库主机上,Auto NUMA的自动迁移可能带来延迟抖动。可在内核启动参数中加入numa_balancing=disable,或运行时关闭:
echo 0 > /proc/sys/kernel/numa_balancing
# 永久生效:grubby --update-kernel=ALL --args="numa_balancing=disable"
四、效果验证与判断依据
调优后,重新采集AWR或使用numastat观察。若numa_miss不再增长,log file sync的P99从18ms降至5ms以内,说明NUMA亲和性改善有效。同时观察mpstat -P ALL 1,确认数据库核的%idle稳定,批处理核的%sys不侵占数据库核。
若延迟仍抖动,需检查是否存在CPU频率调节(cpufreq)导致的降频,或irqbalance将中断分散到数据库核。可将数据库核从irqbalance中排除,或设置isolcpus隔离核。注意:isolcpus会将这些核从通用调度中移除,需配合cpuset使用,否则数据库线程无法使用这些核。
总结来说,CPU调度对数据库响应时间的影响,核心在于“本地化”与“隔离”。NUMA亲和性解决内存访问延迟,调度策略与优先级解决CPU争用。两者结合,才能把P99延迟从不可控的抖动,收敛到可预期的范围。