Vertica Linux IO 调度器性能影响与调优¶
作者:JiangChong | 发布时间:2026-05-08
适用场景: 当你怀疑 IO 调度器配置不匹配导致 Vertica 查询延迟升高、写入吞吐量下降、iowait 持续偏高,或巡检工具报告「IO 调度器不匹配」时,阅读本文。
关联文章:
- Vertica RAID 存储方案 — 存储硬件选型与 RAID 配置
- Vertica Linux Dirty Data 参数调优 — 脏页刷新导致进程挂起的调优
- vioperf测试与dd测试性能差异测试 — IO 性能基准测试方法
- Vertica 监控最佳实践 — 系统级监控全覆盖
理解全文脉络¶
本文先讲 Linux IO 调度器的底层原理(第 1 节),帮助你理解为什么调度器选择会影响 Vertica 这种列存分析型数据库。然后从 系统监控(第 2 节)入手判断是否存在 IO 瓶颈,再 逐步定位(第 3 节)当前调度器是否为问题根因。第 4 节给出 安全切换方案和持久化方法,第 5-6 节通过案例验证,最后提供工具箱速查和最佳实践清单。
如果你已经确认要切换调度器,可直接跳到第 4 节;如果你刚收到巡检告警,从第 3 节开始。
1. Linux IO 调度器原理¶
1.1 IO 调度器是什么¶
IO 调度器是 Linux 内核块层(Block Layer)的核心组件。当应用程序发起读写请求时,请求先进入块层的请求队列,IO 调度器负责对这些请求进行排序、合并和调度,决定哪个请求先发送到磁盘驱动。
通俗比喻: IO 调度器就像机场的航班调度塔——多架飞机(IO 请求)同时申请起降,调度塔决定优先顺序、合并相邻航线,确保跑道(磁盘)不被浪费。
1.2 为什么 Vertica 对 IO 调度器敏感¶
传统 OLTP 数据库(如 MySQL/PostgreSQL)以随机读写为主,数据粒度小(8KB 页),IO 模式分散。而 Vertica 是列存分析型数据库,IO 模式截然不同:
| 特征 | OLTP 数据库 | Vertica |
|---|---|---|
| 典型 IO 大小 | 8KB 随机 | 64KB-1MB 顺序 |
| 读写比例 | 读写混合 | 读多写少(批量写) |
| IO 并发度 | 大量小请求 | 少量大请求+批量加载 |
| 关键指标 | 随机 IOPS | 顺序吞吐量 (MB/s) |
| 调度器敏感度 | 中等 | 高 — 错误调度器会严重拖慢顺序大块读取 |
Vertica 的 ROS container 文件通常以 256KB-512KB 大块顺序读取,COPY 加载以 Direct I/O 批量写入,Tuple Mover mergeout 同时产生大量读写。如果 IO 调度器在不需要的地方自作聪明地重新排序,就会引入额外的延迟。
1.3 多队列调度器(blk-mq)总览¶
Linux 内核 5.0+ 全面转向 blk-mq(多队列块层),单队列 CFQ 和 deadline 被移除,取而代之的是多队列调度器:
| 调度器 | 内核版本 | 设计哲学 | 适合场景 |
|---|---|---|---|
| none (noop) | 所有 | 不做任何调度,FIFO 直接下发 | NVMe SSD — 设备内部已有调度 |
| mq-deadline | 5.0+ | 确保请求不会饿死,读写分离,带 deadline | SATA SSD / HDD — 通用场景 |
| kyber | 5.0+ | 基于延迟目标动态限制派发队列深度 | 低延迟 SSD — 需要控制延迟尾 |
| bfq | 5.0+ | 按 cgroup 公平分配带宽,复杂调度 | 桌面/交互式 — 不适合数据库 |
对 Vertica 的关键结论:
- NVMe SSD 环境 →
none:NVMe 设备内部有大量并行通道和硬件调度,内核调度器是多余的。使用none可以获得最低的 CPU 开销和最低的延迟。 - SATA SSD / RAID 阵列 →
mq-deadline:多队列 deadline 在保证读写公平的同时保持简单的合并策略,是 Vertica 官方推荐的默认选择。 - 低延迟 SSD 且需要控制延迟尾 →
kyber:Kyber 根据延迟反馈动态调整派发深度,适合对延迟一致性要求高的场景。 - 绝对避免
bfq:BFQ 会为每个进程分配带宽份额并做复杂的调度运算,这对数据库的并发大块读写来说纯粹是开销,实测可导致吞吐量下降 30-50%。
1.4 调用路径:Vertica 查询如何经过调度器¶
Vertica 进程(pread/pwrite/Direct I/O)
→ VFS 层(虚拟文件系统)
→ Page Cache(Direct I/O 绕过)
→ 文件系统(ext4/xfs)
→ Block Layer 请求队列
→ IO 调度器 ← 本文焦点
→ SCSI/NVMe 驱动层
→ 磁盘设备
当 Vertica 使用 Direct I/O 读 ROS 文件时,每个 pread() 系统调用直接进入块层,调度器对请求的排序/合并直接影响磁盘的实际服务时间。
2. 系统级 IO 监控¶
在调整调度器之前,需要先确认 IO 是否确实存在瓶颈。以下从 Vertica 内部和 Linux 外部两个维度监控。
2.1 Vertica 内部:system_resource_usage¶
system_resource_usage 是 Vertica 每分钟自动采集的系统资源快照,包含每个节点的 IO 读写速率。
-- 查看各节点最近 5 分钟的 IO 吞吐量
SELECT node_name,
end_time,
io_read_kbytes_per_second,
io_written_kbytes_per_second,
(COALESCE(io_read_kbytes_per_second, 0) + COALESCE(io_written_kbytes_per_second, 0)) AS total_io_kbps,
average_cpu_usage_percent,
average_memory_usage_percent
FROM v_monitor.system_resource_usage
WHERE end_time > SYSDATE - INTERVAL '5 minutes'
ORDER BY end_time DESC;
node_name | end_time | io_read_kbytes_per_second | io_written_kbytes_per_second | total_io_kbps | average_cpu_usage_percent | average_memory_usage_percent
-------------------+---------------------+---------------------------+------------------------------+---------------+---------------------------+------------------------------
v_vmart3_node0001 | 2026-06-02 14:22:00 | 0.53 | 402.81 | 403.34 | 7.23 | 56.28
v_vmart3_node0002 | 2026-06-02 14:22:00 | 277.47 | 341.47 | 618.94 | 2.31 | 73.81
v_vmart3_node0003 | 2026-06-02 14:22:00 | 24.93 | 359.21 | 384.14 | 4.54 | 32.27
v_vmart3_node0001 | 2026-06-02 14:21:00 | 8.4 | 319.21 | 327.61 | 1.99 | 56.31
v_vmart3_node0002 | 2026-06-02 14:21:00 | 8.4 | 408.12 | 416.52 | 2.44 | 73.63
v_vmart3_node0003 | 2026-06-02 14:21:00 | 2.27 | 409.58 | 411.85 | 2.51 | 32.37
v_vmart3_node0001 | 2026-06-02 14:20:00 | 0 | 350.98 | 350.98 | 1.47 | 56.3
v_vmart3_node0002 | 2026-06-02 14:20:00 | 0 | 335.8 | 335.8 | 1.44 | 73.61
v_vmart3_node0003 | 2026-06-02 14:20:00 | 0 | 400.45 | 400.45 | 1.07 | 32.28
v_vmart3_node0001 | 2026-06-02 14:19:00 | 0 | 419.53 | 419.53 | 1.89 | 56.46
(10 rows)
如何解读结果:
total_io_kbps反映了该节点整体的磁盘 IO 吞吐。与存储硬件的额定吞吐对比——例如硬件宣称 800MB/s,但实际只有 200MB/s,说明调度器或队列参数可能有瓶颈。- 如果所有节点的 IO 量接近但某个节点的
average_cpu_usage_percent显著更高,而 iostat 又显示该节点%iowait也高 → 说明 CPU 时间被 IO 等待占据,IO 子系统(含调度器)可能是瓶颈。 - 某个节点的
io_read远低于其他节点 → 可能是数据倾斜导致该节点参与度低,也可能是该节点磁盘性能异常。
2.2 Vertica 内部:io_usage¶
io_usage 提供更细粒度的每分钟 IO 读写统计:
-- 每分钟 IO 读写速率趋势
SELECT node_name,
start_time,
end_time,
read_kbytes_per_sec,
written_kbytes_per_sec,
(COALESCE(read_kbytes_per_sec, 0) + COALESCE(written_kbytes_per_sec, 0)) AS total_kbps
FROM v_monitor.io_usage
WHERE end_time > SYSDATE - INTERVAL '30 minutes'
ORDER BY end_time DESC;
node_name | start_time | end_time | read_kbytes_per_sec | written_kbytes_per_sec | total_kbps
-------------------+---------------------+---------------------+---------------------+------------------------+------------
v_vmart3_node0001 | 2026-06-03 10:44:00 | 2026-06-03 10:45:00 | 0 | 449.15 | 449.15
v_vmart3_node0002 | 2026-06-03 10:44:00 | 2026-06-03 10:45:00 | 0 | 317.15 | 317.15
v_vmart3_node0003 | 2026-06-03 10:44:00 | 2026-06-03 10:45:00 | 0 | 366.93 | 366.93
v_vmart3_node0001 | 2026-06-03 10:43:00 | 2026-06-03 10:44:00 | 0 | 277.49 | 277.49
v_vmart3_node0002 | 2026-06-03 10:43:00 | 2026-06-03 10:44:00 | 12.27 | 432.15 | 444.42
v_vmart3_node0003 | 2026-06-03 10:43:00 | 2026-06-03 10:44:00 | 0 | 392.68 | 392.68
...
如何解读:
- IO 基线:在业务低谷期记录各节点的
total_kbps作为基线。高峰期偏离基线超过 3 倍但仍远低于硬件能力 → 调度器可能不是瓶颈。 - 突发模式:
written_kbytes_per_sec出现间歇性尖峰但read_kbytes_per_sec几乎为 0 → 可能是 Tuple Mover 执行 mergeout。此时如果 iowait 飙升,检查调度器的写批次是否合理。 read_kbytes_per_sec持续低但 CPU 很高:说明查询在大量计算而不是 IO,不是调度器问题。
2.3 Vertica 内部:disk_storage¶
用于确认磁盘空间和存储路径状态:
-- 各节点存储使用情况
SELECT node_name,
storage_usage,
storage_path,
disk_space_used_mb,
disk_space_free_mb,
disk_space_free_percent
FROM v_monitor.disk_storage
ORDER BY node_name, storage_usage;
node_name | storage_usage | storage_path | disk_space_used_mb | disk_space_free_mb | disk_space_free_percent
-------------------+---------------+------------------------------------------------+--------------------+--------------------+-------------------------
v_vmart3_node0001 | CATALOG | /data/vmart3/v_vmart3_node0001_catalog/Catalog | 24220 | 3760 | 13%
v_vmart3_node0001 | DATA,TEMP | /data/vmart3/v_vmart3_node0001_data | 24220 | 3760 | 13%
v_vmart3_node0002 | CATALOG | /data/vmart3/v_vmart3_node0002_catalog/Catalog | 20490 | 7490 | 26%
v_vmart3_node0002 | DATA,TEMP | /data/vmart3/v_vmart3_node0002_data | 20490 | 7490 | 26%
v_vmart3_node0003 | CATALOG | /data/vmart3/v_vmart3_node0003_catalog/Catalog | 22354 | 5626 | 20%
v_vmart3_node0003 | DATA,TEMP | /data/vmart3/v_vmart3_node0003_data | 22354 | 5626 | 20%
(6 rows)
如何解读:
disk_space_free_percent < 20%→ 警告。Vertica 建议保持 40% 空闲空间。磁盘使用率越高,文件的物理碎片越多,IO 调度器的合并和排序效果越差。storage_usage = 'DATA,TEMP'的磁盘是主要的读写目标,是调度器影响的焦点。- 注意
storage_path中不要出现使用系统/tmp/目录作为'DATA,TEMP,CATALOG'。
2.4 Linux 外部:iostat¶
iostat 是 Linux sysstat 包中的 IO 统计工具,提供设备级别的读写指标:
# 查看所有磁盘的扩展统计,每秒刷新
iostat -x 1
Linux 5.14.0-362.8.1.el9_3.aarch64 (v001) 06/03/2026 _aarch64_ (2 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
1.89 0.05 0.66 0.23 0.00 97.17
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz f/s f_await aqu-sz %util
dm-0 0.64 75.24 0.00 0.00 28.35 116.92 3.68 194.84 0.00 0.00 5.57 52.93 0.00 3.54 0.00 0.00 0.03 1284.53 0.00 0.00 0.04 1.03
dm-1 0.37 1.47 0.00 0.00 7.38 4.00 0.37 2.47 0.00 0.00 106.54 6.66 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.04 0.10
sda 0.88 76.74 0.18 16.98 25.26 87.51 2.73 197.31 1.39 33.70 6.29 72.18 0.00 3.94 0.00 0.00 0.03 1424.62 0.35 1.37 0.04 1.07
sr0 0.00 0.02 0.00 0.00 0.64 4.15 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
关键指标解读:
| 指标 | 含义 | Vertica 相关阈值 |
|---|---|---|
%iowait |
CPU 等待 IO 完成的时间占比 | > 10% 持续 → IO 瓶颈 |
aqu-sz |
平均请求队列深度 | > 10 → 调度器可能在积压请求 |
r_await / w_await |
读/写平均延迟(ms) | > 10ms (SSD) / > 50ms (HDD) → 延迟偏高 |
%util |
磁盘繁忙时间占比 | > 80% 持续 → 吞吐接近饱和 |
rMB/s / wMB/s |
每秒读写吞吐量 | 对比硬件额定值 |
对于 SSD,%util 高不一定意味着真正的瓶颈——SSD 可以并行处理请求,单个请求队列只是 SSD 内部通道之一。更应该关注 aqu-sz 和 r_await/w_await。
3. 逐步定位:IO 调度器是否为根因¶
以下按排查优先级逐步推进。每一步如果不能确认问题,进入下一步。
3.1 检查当前调度器¶
# 查看所有块设备的调度器
cat /sys/block/sda/queue/scheduler
# 输出:[mq-deadline] kyber bfq none
# ↑ 方括号内的为当前生效的调度器
如何解读:
- 方括号
[mq-deadline]表示当前生效的调度器。 - 如果 NVMe 设备(
nvme0n1)显示[mq-deadline]→ 不符合最佳实践,应切换为none。 - 如果 SATA SSD / RAID 阵列显示
[bfq]→ 严重问题,bfq 不适合数据库场景。 - 如果显示
[none]但这是 SATA HDD → 可能导致写请求饿死读请求,需要考虑mq-deadline。
3.2 判断是否 NVMe 设备¶
NVMe 设备需要使用 none 调度器。如何判断?
# 方法1:检查块设备名称——NVMe 设备以 nvme 开头
ls /dev/nvme* 2>/dev/null && echo "检测到 NVMe 设备" || echo "无 NVMe 设备"
# 方法2:检查 rotational 标志(0=SSD, 1=HDD)
cat /sys/block/sda/queue/rotational
# 输出 0 = SSD(包括 SATA SSD 和 NVMe),1 = HDD
对于 NVMe 设备,通过传输层判断:
对于 NVMe,必须使用 none。 NVMe 的提交队列(Submission Queue)和完成队列(Completion Queue)机制已经实现了硬件级并行调度,内核调度器的干预反而增加了不必要的 CPU 开销和延迟。
3.3 对比 IO 性能与调度器关联¶
如果你怀疑当前调度器是瓶颈(例如刚更换过调度器或刚发现使用了 bfq),可以用以下方式对比:
# 运行 iostat 收集 60 秒数据
iostat -x 1 60 > /tmp/iostat_before.txt
# 临时切换到目标调度器(在线切换,立即生效,不需重启)
echo none > /sys/block/sda/queue/scheduler
# 再收集 60 秒数据
iostat -x 1 60 > /tmp/iostat_after.txt
# 对比两次的 r_await/w_await 和 %util
# 恢复原调度器
echo mq-deadline > /sys/block/sda/queue/scheduler
判断标准:
- 切换到
none(NVMe)后r_await降低 > 20% → 确认原调度器有开销。 - 切换到
mq-deadline(SATA SSD)后w_await显著下降 → bfq 的公平调度在拖慢写请求。 - 如果切换后指标没有显著变化 → IO 瓶颈不在调度器层面,需要排查其他方向(见 3.5)。
3.4 分析 iowait 与调度器的关系¶
当 iowait 持续偏高时,需要区分是磁盘物理能力不足还是调度器延迟引入:
# 查看各 CPU 的 iowait 分布
mpstat -P ALL 1 5
Linux 5.14.0-362.8.1.el9_3.aarch64 (v001) 06/03/2026 _aarch64_ (2 CPU)
10:56:08 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10:56:09 AM all 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
10:56:09 AM 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
10:56:09 AM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
10:56:09 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10:56:10 AM all 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
10:56:10 AM 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
10:56:10 AM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
解读:
- 如果 iowait 集中在少数几个 CPU 上 → 可能是中断亲和性(IRQ affinity)问题,而非调度器问题。详见关联文章(vault 中暂无 IRQ affinity 专题,此处为方向性建议)。
- 如果所有 CPU 的 iowait 都很均匀 → 更可能是磁盘瓶颈或调度器问题。
3.5 排除其他根因¶
在确定调度器是根因之前,依次排除以下常见 IO 问题:
| 问题 | 检查方法 | 关联文章 |
|---|---|---|
| 脏页堆积导致 IO 阻塞 | cat /proc/meminfo \| grep Dirty |
Vertica Linux Dirty Data 参数调优 |
| ROS Container 过多 | SELECT ... FROM v_monitor.projection_storage GROUP BY ... |
Vertica 监控最佳实践 |
| 磁盘接近满载 | v_monitor.disk_storage 中 disk_space_free_percent |
本文 2.3 |
| RAID 卡缓存配置不当 | 硬件厂商工具检查 | Vertica RAID 存储方案 |
| 磁盘物理故障 | dmesg \| grep -i error + smartctl -a /dev/sda |
— |
4. 解决方案:切换 IO 调度器¶
4.1 在线切换(立即生效,无需重启)¶
# 1. 查看当前调度器和可用选项
cat /sys/block/sda/queue/scheduler
# 输出示例:none [mq-deadline] kyber bfq
# 2. 切换到目标调度器
# NVMe SSD → none
echo none > /sys/block/sda/queue/scheduler
# SATA SSD / RAID HDD → mq-deadline
echo mq-deadline > /sys/block/sda/queue/scheduler
# 低延迟 SSD 场景 → kyber
echo kyber > /sys/block/sda/queue/scheduler
# 3. 确认切换生效
cat /sys/block/sda/queue/scheduler
# 输出:none [mq-deadline] kyber bfq → 方括号内为当前生效
重要: 在线切换对正在运行的 Vertica 进程无影响——IO 调度器运行在块层,切换只影响后续提交的请求。已在队列中的请求继续按旧调度器处理。
安全提示: 在线切换不持久。重启后恢复默认调度器。如果验证效果良好,必须执行 4.2 的持久化。
4.2 持久化配置¶
有两种方法使调度器配置在系统重启后保持:
方法 A:udev 规则(推荐,按设备类型精确匹配)¶
创建 /etc/udev/rules.d/60-iosched.rules:
cat > /etc/udev/rules.d/60-iosched.rules << 'EOF'
# NVMe SSD → none 调度器
ACTION=="add|change", KERNEL=="nvme*[0-9]n*[0-9]", ATTR{queue/scheduler}="none"
# SATA/SAS SSD (rotational=0) → mq-deadline
ACTION=="add|change", KERNEL=="sd*[!0-9]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# HDD (rotational=1) → mq-deadline
ACTION=="add|change", KERNEL=="sd*[!0-9]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="mq-deadline"
EOF
# 重新加载 udev 规则
udevadm control --reload-rules
udevadm trigger
为什么用 udev 而不是 grub:
- udev 规则可以按设备类型(NVMe vs SATA、SSD vs HDD)精确匹配,不同设备使用不同调度器。
- grub 的
elevator=参数是全局的,所有设备用同一个调度器,不灵活。 - 如果系统只有一种设备类型,用 grub 也可以(见方法 B)。
方法 B:grub 内核参数(简单但全局生效)¶
# 编辑 /etc/default/grub,在 GRUB_CMDLINE_LINUX 中加入 elevator 参数
# 例如:GRUB_CMDLINE_LINUX="... elevator=none"
# 或: GRUB_CMDLINE_LINUX="... elevator=mq-deadline"
# 重新生成 grub 配置(RHEL/CentOS)
grub2-mkconfig -o /boot/grub2/grub.cfg
# 或者(Ubuntu/Debian)
update-grub
elevator 参数的取值与 /sys/block/<dev>/queue/scheduler 的取值一致:none、mq-deadline、kyber。
4.3 mq-deadline 微调参数¶
如果选择了 mq-deadline,还可以调整其内部参数以更好地适配 Vertica 的 IO 模式:
| 参数 | 默认值 | Vertica 建议 | 说明 |
|---|---|---|---|
read_expire |
500ms | 保持默认 | 读请求在队列中的最长等待时间。Vertica 以读为主,不应增加 |
write_expire |
5000ms | 降为 2000-3000ms | 写请求最长等待时间。Vertica 批量写不应等待太久 |
writes_starved |
2 | 保持默认 | 写批次处理多少次读批次后才强制处理一次写。2 意味着读优先 |
fifo_batch |
16 | 改为 32-64 | 每批处理的请求数。增加可提升顺序 IO 的合并效率 |
front_merges |
1 | 保持 1 | 是否允许前向合并。对顺序 IO 友好 |
为什么 write_expire 要降低: Vertica 的 COPY 加载和 Tuple Mover mergeout 会产生大量写请求。默认 5000ms 意味着最多等 5 秒才必须处理一次写批次。在这 5 秒内,如果有大量读请求持续到来,写请求会被持续推迟。降低到 2000-3000ms 可减少写延迟峰值。
# 在线修改 mq-deadline 参数(立即生效,重启后恢复默认)
echo 2000 > /sys/block/sda/queue/iosched/write_expire # 写过期时间降为 2 秒
echo 64 > /sys/block/sda/queue/iosched/fifo_batch # 增加批次大小
# 持久化:加入 udev 规则
# ATTR{queue/iosched/write_expire}="2000"
# ATTR{queue/iosched/fifo_batch}="64"
4.4 Vertica 推荐的调度器总结¶
| 存储类型 | 推荐调度器 | 原因 |
|---|---|---|
| NVMe SSD | none |
NVMe 有硬件级多队列,内核调度器是多余的 |
| SATA/SAS SSD | mq-deadline |
读写公平 + 简单合并,开销最低 |
| RAID 阵列(HDD/SSD) | mq-deadline |
顺序 IO 友好,不引入不必要延迟 |
| SAN / 虚拟化存储 | none 或 mq-deadline |
取决于底层存储能力,优先测试 none |
| Eon Mode Depot (NVMe) | none |
Depot 以顺序预取和批量刷写为主 |
5. 深入案例¶
5.1 虚构案例:bfq 导致 ETL 写入严重降速¶
📝 虚构案例
场景: 某金融机构 3 节点 Vertica 集群(Enterprise 模式),SATA SSD RAID 10 阵列,每晚 ETL 批量加载 2 亿行数据。运维团队在系统更新后,夜间 ETL 加载时间从 45 分钟暴增到 3 小时。
诊断过程:
# 1. 检查调度器——发现是 bfq
cat /sys/block/sda/queue/scheduler
# 输出:mq-deadline kyber [bfq] none
# ↑ bfq 正在使用!
-- 2. 查看 ETL 执行时段的 IO 写入吞吐
SELECT node_name,
end_time,
written_kbytes_per_sec
FROM v_monitor.io_usage
WHERE end_time BETWEEN '2026-05-20 22:00:00' AND '2026-05-21 02:00:00'
ORDER BY end_time DESC;
node_name | end_time | written_kbytes_per_sec
-------------------+---------------------+------------------------
v_vmart3_node0001 | 2026-05-20 23:55:00 | 100493
v_vmart3_node0002 | 2026-05-20 23:55:00 | 96388
v_vmart3_node0003 | 2026-05-20 23:55:00 | 91877
v_vmart3_node0001 | 2026-05-20 23:54:00 | 97841
v_vmart3_node0002 | 2026-05-20 23:54:00 | 88452
v_vmart3_node0003 | 2026-05-20 23:54:00 | 108332
...
解读: 各节点写入速率在 88,000-108,000 KB/s(约 86-106 MB/s),三节点聚合约 270-300 MB/s——但硬件 RAID 10 阵列额定写入能力为 500 MB/s,设备利用率仅约 55-60%。bfq 调度器在内核层面对 IO 带宽做了进程级拆分,导致硬件能力未被充分利用。
# 3. 查看 iostat 确认
iostat -x 1 5
# Device r/s rkB/s w/s wkB/s aqu-sz %util
# sda 200 80000 50 25000 2.3 35%
# ↑ 硬件空闲,队列深度只有 2.3
根因分析: bfq 调度器按 cgroup/进程 公平分配 IO 带宽,Vertica 的多个后台线程(Tuple Mover、EE 线程、加载线程)被 bfq 视为多个竞争进程,各自分得很小的带宽份额。结果是大量时间浪费在内核调度计算上,设备利用率极低。
修复方案:
效果对比:
| 指标 | 修复前 (bfq) | 修复后 (mq-deadline) |
|---|---|---|
| ETL 总耗时 | 180 min | 48 min |
| 写入吞吐 | 80-120 MB/s | 400-480 MB/s |
平均 w_await |
45ms | 3.2ms |
| 磁盘 %util | 35% | 95% |
5.2 虚构案例:NVMe 使用 mq-deadline 导致延迟尾偏高¶
📝 虚构案例
场景: 某电信运营商 5 节点 Eon Mode 集群,节点配备 NVMe SSD 作为 Depot。监控显示 P99 查询延迟从 2 秒飙升至 8 秒,但 P50 仍然正常(0.5 秒)。iostat 显示 r_await 平均 2ms 但 aqu-sz 峰值达到 32。
诊断过程:
# 1. 发现 NVMe 在用 mq-deadline
cat /sys/block/nvme0n1/queue/scheduler
# 输出:[mq-deadline] kyber bfq none
根因分析: NVMe 设备有 64K 级别的硬件队列深度(Submission Queue),但 mq-deadline 的软件调度将请求限制在 256 的 nr_requests 内,并施加 deadline 排序。这不仅浪费了 NVMe 的并行能力,还在突发负载时引入额外的排队延迟。
修复方案:
echo none > /sys/block/nvme0n1/queue/scheduler
# 同时提升 nr_requests 以匹配 NVMe 的并行能力
echo 1024 > /sys/block/nvme0n1/queue/nr_requests
效果对比:
| 指标 | 修复前 | 修复后 |
|---|---|---|
| P99 查询延迟 | 8000ms | 1100ms |
| P50 查询延迟 | 500ms | 350ms |
r_await P99 |
25ms | 4ms |
aqu-sz 峰值 |
32 | 8 |
5.3 真实案例:某运营商系统更新后 IO 调度器被重置¶
📋 真实案例 · 来源:20231115某运营商Vertica数仓性能问题处理报告
背景: 某运营商 Vertica 集群在系统补丁更新后,查询性能普遍下降 30-40%。用户反映「同样的 SQL 以前 10 秒出结果,现在要 15-20 秒」。
诊断过程(摘录):
- 检查 CPU、内存指标:正常
- 检查
query_requests慢查询:执行时间普遍增加但无明确瓶颈 - 检查 Linux 层面:
iostat -x 1发现%iowait从 2-3% 升至 8-12% - 对比发现:系统更新后 grub 配置被重置,IO 调度器从
mq-deadline变为bfq
修复: 恢复 mq-deadline 调度器并添加 udev 规则防止再次被覆盖。
效果: 查询性能恢复正常水平,%iowait 回落至 2-3%。
6. 完整诊断流程实战¶
📝 虚构场景 · 完整演练
背景: 你收到巡检工具告警:「节点 node0002 IO 调度器 = bfq,推荐 = mq-deadline」。以下是完整的排查和修复过程。
时间线:
14:00 — 收到告警,确认告警内容:
14:05 — 评估影响范围(Vertica 侧):
-- 对比各节点的 IO 与 CPU 差异
SELECT node_name,
end_time,
io_read_kbytes_per_second,
io_written_kbytes_per_second,
average_cpu_usage_percent
FROM v_monitor.system_resource_usage
WHERE end_time > SYSDATE - INTERVAL '1 hour'
ORDER BY end_time DESC
LIMIT 30;
node_name | end_time | io_read_kbytes_per_second | io_written_kbytes_per_second | average_cpu_usage_percent
-------------------+---------------------+---------------------------+------------------------------+---------------------------
v_vmart3_node0001 | 2026-06-03 14:22:00 | 527.33 | 388.12 | 5.23
v_vmart3_node0002 | 2026-06-03 14:22:00 | 201.47 | 351.69 | 18.47 ← CPU 高但 IO 低!
v_vmart3_node0003 | 2026-06-03 14:22:00 | 489.91 | 372.28 | 4.98
v_vmart3_node0001 | 2026-06-03 14:21:00 | 510.05 | 401.33 | 4.87
v_vmart3_node0002 | 2026-06-03 14:21:00 | 187.62 | 358.44 | 17.92 ← 持续异常
v_vmart3_node0003 | 2026-06-03 14:21:00 | 475.18 | 389.71 | 4.55
(30 rows)
解读: node0002 的 io_read_kbytes_per_second(~200 KB/s)只有其他节点(~500 KB/s)的 40%,但 average_cpu_usage_percent(~18%)反而是其他节点(~5%)的 3-4 倍。CPU 被浪费在 bfq 的进程级带宽分配计算上,而非服务实际 IO 请求。
14:10 — 确认磁盘类型(判断目标调度器):
14:12 — 在线切换:
echo mq-deadline > /sys/block/sda/queue/scheduler
cat /sys/block/sda/queue/scheduler
# 确认:none [mq-deadline] kyber bfq ✓
14:20 — 验证效果:
-- 查询近期 IO 使用是否变化
SELECT node_name, end_time,
read_kbytes_per_sec, written_kbytes_per_sec
FROM v_monitor.io_usage
ORDER BY end_time DESC
LIMIT 5;
14:30 — 持久化配置:
cat > /etc/udev/rules.d/60-iosched.rules << 'EOF'
ACTION=="add|change", KERNEL=="sd*[!0-9]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
EOF
udevadm control --reload-rules
14:35 — 检查其他节点(防止遗漏):
# 在所有节点上执行
for host in node0001 node0002 node0003; do
ssh $host 'cat /sys/block/sda/queue/scheduler'
done
最终确认: 三个节点统一为 mq-deadline,告警清除。后续观察 24 小时,IO 吞吐恢复至正常水平。
7. 快速诊断 SQL / 命令工具箱¶
SQL 工具箱¶
| 诊断目标 | SQL | 已验证版本 |
|---|---|---|
| 各节点 IO 吞吐趋势 | SELECT node_name, end_time, io_read_kbytes_per_second, io_written_kbytes_per_second FROM v_monitor.system_resource_usage ORDER BY end_time DESC LIMIT 10; |
v26.1.0-2 |
| 每分钟 IO 读写速率 | SELECT node_name, start_time, read_kbytes_per_sec, written_kbytes_per_sec FROM v_monitor.io_usage WHERE end_time > SYSDATE - INTERVAL '30 minutes' ORDER BY end_time DESC; |
v26.1.0-2 |
| 各节点磁盘使用率 | SELECT node_name, storage_usage, storage_path, disk_space_used_mb, disk_space_free_mb, disk_space_free_percent FROM v_monitor.disk_storage ORDER BY node_name, storage_usage; |
v26.1.0-2 |
| 当前运行的查询(排查是否有大查询导致 IO 高) | SELECT node_name, query, query_start, user_name, is_executing FROM v_monitor.query_profiles WHERE is_executing = 't'; |
v26.1.0-2 |
| 查看节点状态 | SELECT node_name, node_state FROM nodes ORDER BY 1; |
v26.1.0-2 |
Linux 命令工具箱¶
| 诊断目标 | 命令 | 备注 |
|---|---|---|
| 查看当前调度器 | cat /sys/block/sd*/queue/scheduler |
方括号内为当前生效 |
| 查看磁盘类型(SSD/HDD) | cat /sys/block/sda/queue/rotational |
0=SSD, 1=HDD |
| 检查是否为 NVMe | ls /dev/nvme* |
有输出 = NVMe |
| IO 实时监控 | iostat -x 1 |
关注 %iowait, aqu-sz, r_await/w_await |
| 查看 IO 调度器参数 | ls /sys/block/sda/queue/iosched/ |
mq-deadline 可调参数列表 |
| 在线切换调度器 | echo <scheduler> > /sys/block/sda/queue/scheduler |
立即生效,重启后失效 |
| 查看 CPU 中断分布 | mpstat -P ALL 1 5 |
区分全局 vs 局部 iowait |
| 持久化确认 | ls /etc/udev/rules.d/60-iosched.rules |
检查 udev 规则是否存在 |
| grub 调度器参数检查 | cat /proc/cmdline \| grep elevator |
有输出 = 已通过 grub 配置 |
8. 最佳实践清单¶
按投入产出比排序:
- 部署时即设定 IO 调度器:不要在运行中才发现。新节点部署时,直接通过 udev 规则设置
none(NVMe)或mq-deadline(SATA/RAID)。为什么: 省去事后排查和在线切换的时间。 - 巡检中加入调度器检查:在每个节点的日常巡检中添加
cat /sys/block/*/queue/scheduler。为什么: 系统更新/补丁可能重置调度器配置(见 5.3 真实案例)。 - NVMe 必须用
none,SATA SSD/RAID 用mq-deadline:不要反向。为什么: NVMe 的硬件多队列已经是最优调度,软件调度器只会增加延迟和 CPU 开销。 - 绝对避免
bfq:bfq 为桌面交互设计,数据库场景下吞吐量可损失 30-50%。为什么: bfq 按进程公平分配带宽,Vertica 的多线程架构反而被惩罚。 - 在线切换前先确认磁盘类型:
rotational、/dev/nvme*确认后再切换。为什么: 错误地将 HDD 设为none会导致写请求饿死读请求。 - 切换后必须持久化:
echo到 sysfs 只对当前启动有效。通过 udev 规则或 grub 参数持久化。为什么: 避免重启后问题复现。 - mq-deadline 场景下调低
write_expire:从 5000ms 降至 2000-3000ms。为什么: Vertica 批量写入不应在队列中积压过久。 none调度器下增大nr_requests:NVMe 使用none时,将nr_requests设为 1024 或更高。为什么: NVMe 的硬件队列深度极大(64K+),256 的默认值限制了并行度。- 磁盘使用率不要超过 60%:Vertica 建议保持 40% 空闲空间。为什么: 使用率越高,文件碎片越多,调度器的合并和排序效率越差,且与调度器选择无关——再好的调度器也救不了满盘。
- 集群所有节点统一调度器:不要让 node1 用
mq-deadline、node2 用bfq。为什么: Vertica 是 shared-nothing 架构,查询在慢节点上等结果,最慢的节点决定整体查询延迟。
扩展阅读¶
- Vertica Linux Dirty Data 参数调优 — 脏页刷新导致 IO 阻塞的调优方案
- Vertica RAID 存储方案 — 存储硬件选型与 RAID 配置
- Vertica 监控最佳实践 — 系统级 IO 监控 SQL 大全
- Vertica CPU 持续高负载诊断与优化 — 系统级性能诊断与调优