...

Настройка планировщика ввода-вывода ядра: оптимизация для повышения производительности хостинга

С помощью I/O Scheduler Tuning я специально оптимизирую Ядро-путь для доступа к памяти и уменьшить задержки в хостинговых средах. В статье на практике показано, как я адаптирую дисковое планирование Linux к аппаратным средствам и рабочей нагрузке, чтобы хостинг безопасное исполнение.

Центральные пункты

Следующие ключевые моменты дадут вам краткий обзор содержания этой статьи.

  • Выбор планировщикаNoop/none, mq-deadline, BFQ, Kyber в зависимости от аппаратного обеспечения и рабочей нагрузки
  • стратегия измеренияFio, iostat, P95/P99, IOPS и пропускная способность до/после изменений
  • Тонкие настройки: Readahead, RQ-Affinity, Cgroups, ionice для QoS
  • Настойчивость: правила udev и параметры GRUB для постоянных профилей
  • ПрактикаУстранение неполадок, связанных с пиковыми значениями задержки, справедливостью и особенностями NVMe

Как работает планирование дисков в Linux

Я вижу планировщик ввода-вывода как центр управления, который преобразует запросы в Кии сортирует, объединяет и расставляет приоритеты. На жестких дисках я избегаю дорогостоящих перемещений головки, организуя запросы по адресам блоков и тем самым сокращая время поиска. На SSD и NVMe доминирует параллелизм, поэтому многоочередная подсистема blk-mq делает путь шире и устанавливает приоритет для нескольких запросов. Процессоры распределенной. Это уменьшает задержки, сглаживает пики и поддерживает пропускную способность на должном уровне, даже если многие службы пишут и читают одновременно. В хостинге веб-серверы, базы данных и задания резервного копирования работают вместе, поэтому я всегда согласовываю планирование с доминирующими моделями доступа.

Краткое описание распространенных планировщиков

Для NVMe и современных SSD я часто выбираю нет (эквивалент Noop в контексте blk-mq), потому что контроллер оптимизирован внутри и любые дополнительные накладные расходы стоят денег. mq-deadline устанавливает фиксированные сроки для чтения и записи, приоритизирует операции чтения и обеспечивает постоянное время отклика при смешанной нагрузке на сервер. BFQ справедливо распределяет полосу пропускания между процессами и подходит для многопользовательских систем, в которых отдельные ВМ иначе занимали бы диск. Kyber стремится к низким задержкам и замедляет входящие запросы при превышении целевого времени. CFQ считается устаревшим решением и вряд ли подходит для NVMe; я использую CFQ только в тех случаях, когда этого требуют устаревшие системы или когда тесты показывают явные преимущества; подробный обзор я привожу здесь: Руководство по планировщику ввода/вывода.

Пошаговая настройка планировщика ввода-вывода

Я начинаю с четкого Базовый уровень-измерения, чтобы я мог объективно показать прирост. Я использую fio для синтетических шаблонов, iostat для статистики устройств и собираю задержки P95/P99 для чтения и записи. Затем я проверяю активный планировщик для каждого устройства и меняю его во время выполнения, чтобы быстро провести контртестирование. Я вношу постоянные изменения только тогда, когда стабильные измерения показывают, что выбор правильный. Таким образом, я избегаю ошибочных решений, которые впоследствии вынуждают делать дорогостоящий откат.

# Проверка текущего планировщика
cat /sys/block//queue/scheduler

# Изменение на лету (пример: nvme0n1 на mq-deadline)
echo mq-deadline | sudo tee /sys/block/nvme0n1/queue/scheduler

# Быстрое сравнение с помощью fio (случайные чтения 4k)
fio --name=rr --rw=randread --bs=4k --iodepth=32 --numjobs=4 --runtime=60 --filename=/dev/nvme0n1

Я слежу за загрузкой процессора, потому что неподходящий планировщик создает дополнительные переключения контекста и тем самым снижает чистую производительность. Как только задержки падают, а пропускная способность увеличивается, я сохраняю решение и документирую профили тестирования. За каждым шагом следует изменение, затем измерение, чтобы я мог четко разделить причину и следствие. Такая дисциплина приносит свои плоды, когда на сервере установлено несколько классов дисков и отдельные устройства реагируют по-разному.

Тонкие настройки: Readahead, RQ-Affinity, Cgroups

Выбрав планировщик, я настраиваю Очередь-параметр для загрузки. Для последовательного резервного копирования я повышаю readahead, для случайного ввода-вывода - понижаю, чтобы не загружать лишние страницы. С помощью RQ affinity я гарантирую, что завершения будут приземляться на ядро, сгенерировавшее запрос, что улучшает латентность и локальность кэша. Я использую ionice для понижения уровня таких процессов, как резервное копирование и индексирование, чтобы веб-запросы не страдали. В многопользовательских средах я регулирую пропускную способность и IOPS с помощью Cgroups v2, чтобы установить жесткие ограничения для каждого клиента.

# Readahead для последовательных шаблонов
echo 128 | sudo tee /sys/block//queue/read_ahead_kb

# RQ affinity: 2 = завершение на генерирующем ядре
echo 2 | sudo tee /sys/block//queue/rq_affinity

# Завершение процесса резервного копирования
ionice -c2 -n7 -p 

# Cgroup v2: вес и ограничение (пример major:minor 8:0)
echo 1000 | sudo tee /sys/fs/cgroup/hosting/io.weight
echo "8:0 rbps=50M wbps=25M" | sudo tee /sys/fs/cgroup/hosting/io.max

Какой вариант подойдет для размещения профилей?

Я решаю планировщик-Выбор в соответствии с классом оборудования, шаблоном доступа и размером цели (задержка против пропускной способности против справедливости). SSD NVMe в однопользовательских виртуальных машинах, как правило, не имеют преимуществ, поскольку контроллер выполняет обширную оптимизацию, и каждый программный уровень имеет значение. Для смешанных нагрузок чтения/записи на SSD я часто использую mq-deadline, поскольку он устанавливает приоритет запросов на чтение и тем самым защищает время отклика. В средах виртуального хостинга я выбираю BFQ, чтобы обеспечить справедливость между клиентами и предотвратить монополизацию полосы пропускания. Я использую Kyber, когда критически важны целевые задержки и приходится придерживаться жестких ограничений для определенных рабочих нагрузок.

планировщик Подходящее оборудование Типичные рабочие нагрузки Преимущества Примечания
Нет/нет NVMe, современный твердотельный накопитель Множество параллельных операций чтения/записи, виртуальные машины Минимальные накладные расходы, высокий уровень параллелизма Контроллер берет на себя сортировку; тест в SAN/RAID
mq-deadline SSD, SAS, быстрый жесткий диск Смешанные нагрузки на веб/БД Приоритет отдан задержкам чтения, хорошая пропускная способность Конечные значения консервативны; возможна корректировка
BFQ SSD/HDD в многопользовательском режиме Множество пользователей, cgroups Четкая справедливость и контроль полосы пропускания Некоторые административные усилия, чистая взвешенность
Kyber SSD, NVMe Услуги, критичные к задержкам Контролируемая задержка при достижении цели Точное измерение для правильной настройки дросселирования
CFQ Устаревшее оборудование Устаревшие рабочие нагрузки Прежний стандартный раствор Редко бывает полезен на современных NVMe/SSD

Практические профили и измеренные значения

Для веб-серверов с большим количеством маленьких Читает Задержка P95 имеет большее значение, чем чистый IOPS, поэтому я тестирую запросы на получение с keep-alive и TLS в сочетании. При работе с базами данных возникает необходимость в синхронной записи, поэтому я моделирую поведение flush и затраты на fsync с помощью файлов заданий fio. Окна резервного копирования часто имеют последовательные потоки; здесь я измеряю пропускную способность в МБ/с и слежу за тем, чтобы запросы фронтенда не ждали слишком долго. В своих тестах я наблюдаю сокращение времени отклика на 20-50 %, в зависимости от исходной ситуации, если планировщик и readahead соответствуют рабочей нагрузке. Если вам нужно больше информации об измерении пропускной способности диска, вы можете найти введение здесь: Пропускная способность диска в хостинге.

Постоянная настройка и автоматизация

Я закрепляю Выбор постоянно через правило udev, чтобы после перезагрузки устройства запускались непосредственно в соответствующем режиме. Я часто устанавливаю none для NVMe, mq-deadline для SSD и BFQ для вращающихся носителей, если справедливость имеет первостепенное значение. При необходимости я устанавливаю глобальное значение по умолчанию через GRUB, если я использую однородную установку. Я придерживаюсь коротких правил и документирую их в репозитории конфигурации, чтобы команда могла их отслеживать. Для более глубокой оптимизации ядра эта статья дополняет настройку: Производительность ядра в хостинге.

# /etc/udev/rules.d/60-ioschedulers.rules

# NVMe: нет
ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"

Твердотельные накопители #: mq-deadline
ACTION=="add|change", KERNEL=="sd[a-z]|vd[a-z]", ATTR{rotational}=="0", ATTR{queue/scheduler}="mq-deadline"

Жесткие диски #: BFQ
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{rotational}=="1", ATTR{queue/scheduler}="bfq"

# Перезагрузка/тестирование правил
udevadm control --reload
udevadm trigger
# Дополнительное глобальное значение по умолчанию через GRUB
# /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="elevator=mq-deadline"
update-grub

QoS с помощью Cgroups v2 и ionice

Чтобы ни одна работа не осталась без внимания заблокировано, Я полагаюсь на правила QoS с помощью Cgroups v2 и добавляю приоритеты через ionice. Для премиум-арендаторов я повышаю io.weight, а для шумных соседей устанавливаю жесткие ограничения с помощью io.max. Я привязываю модули systemd непосредственно к Cgroups, чтобы службы автоматически переходили в нужный класс при запуске. Я временно ограничиваю краткосрочную работу по обслуживанию, чтобы запросы клиентов продолжали поступать без сбоев. Такое взаимодействие весов, лимитов и приоритетов процессов создает предсказуемое время отклика даже под нагрузкой.

# Создайте cgroup и установите ограничения
mkdir -p /sys/fs/cgroup/hosting
echo 1000 | tee /sys/fs/cgroup/hosting/io.weight
echo "8:0 rbps=100M wbps=60M" | tee /sys/fs/cgroup/hosting/io.max

Переместите процесс # в группу Cgroup
echo  | tee /sys/fs/cgroup/hosting/cgroup.procs

# Низкий приоритет ввода-вывода для вторичных заданий
ionice -c2 -n7 -p

Мониторинг и устранение неполадок

Я всегда храню телеметрию закрыть на рабочие нагрузки, иначе я упущу решения. Я использую iostat для чтения времени обслуживания и глубины очередей, blktrace для анализа потоков запросов и sar/dstat для просмотра загрузки системы во времени. Что касается задержек, то я смотрю не только на средние значения, но и всегда на P95/P99, потому что там становятся видны заметные заминки. Если P95 хорошо, а P99 - нет, я корректирую глубину очереди или RQ affinity и проверяю конкурирующие задания. После каждой корректировки я сравниваю одни и те же ключевые показатели, чтобы эффект оставался достоверным.

Типичные камни преткновения и способы их устранения

Высокий Латентность на SSD часто указывает на неподходящий планировщик; тогда я сразу же тестирую mq-deadline и проверяю, стало ли чтение быстрее. Я решаю проблему несправедливого распределения в многопользовательских системах с помощью BFQ и очищаю веса Cgroup, чтобы сильные клиенты не вытесняли слабых. Тайм-ауты NVMe указывают на прошивку или слишком агрессивный опрос; в таких случаях я отключаю io_poll и снижаю глубину, пока не восстановится стабильность. Колебания пропускной способности в окнах резервного копирования часто можно сгладить с помощью настроенного readahead, особенно если преобладают большие файлы. Если одновременно вращается несколько факторов, я действую пошагово: одно изменение, затем измерение, затем следующее.

Настройки планировщика в деталях

После того как основной выбор сделан, я поворачиваю регулировочные винты соответствующих планировщиков. Я всегда начинаю с просмотра доступных параметров для каждого устройства, поскольку они зависят от ядра и дистрибутива.

# Отображение доступных настроек
ls -1 /sys/block//queue/iosched
cat /sys/block//queue/iosched/*

# Пример: mq-deadline более консервативен для заданий с большим объемом записи
echo 100 | sudo tee /sys/block//queue/iosched/read_expire
echo 500 | sudo tee /sys/block//queue/iosched/write_expire
echo 1 | sudo tee /sys/block//queue/iosched/front_merges

# Пример: BFQ для более строгой справедливости и меньшего времени простоя
echo 1 | sudo tee /sys/block//queue/iosched/low_latency
echo 0 | sudo tee /sys/block//queue/iosched/slice_idle

В mq-deadline я в основном регулирую read_expire/write_expire (в миллисекундах) и front_merges для объединения отложенных запросов. При использовании BFQ, в зависимости от плотности арендаторов, я переключаю низкая задержка и slice_idle, чтобы сократить время ожидания между потоками. Я документирую каждое изменение с помощью измеренных значений, так как неправильное истечение времени может вызвать нежелательные пики задержек в условиях резкой нагрузки.

Параметры файловой системы и монтирования

Настройка планировщика начинает работать только тогда, когда файловая система совпадает. Я обращаю внимание на:

  • относительное время/безвременьеИзбегайте ненужной записи метаданных.
  • отбрасывание против фстрима: На SSD/NVMe я обычно использую периодический fstrim вместо online discard, чтобы избежать пиков задержки.
  • ЖурналДля ext4 хорошо зарекомендовали себя следующие данные=упорядоченные (по умолчанию) и подходящий commit=-интервал (например, 10-30 с в зависимости от допустимости потери данных).
  • БарьерыБарьеры записи остаются активными; я не деактивирую их, если только аппаратное обеспечение не гарантирует защиту от сбоев питания (батарея/конденсатор).
# Пример /etc/fstab для ext4
UUID= /data ext4 defaults,noatime,commit=20 0 2

# Включите периодический TRIM вместо опции отбрасывания
systemctl enable fstrim.timer
systemctl start fstrim.timer

Для XFS я также установил noatime и предпочитаю fstrim.timer. Журнальные или барьерные опции зависят от дистрибутива; я всегда тестирую конкретную комбинацию ядра/FS и измеряю P95/P99.

RAID, LVM, DM-crypt и Multipath

В стековых установках (Device Mapper, LVM, mdraid, Multipath) я определяю планировщик там, где приложение видит ввод-вывод - т. е. на Устройство верхнего уровня - и предотвратить двойную сортировку под ними.

# Установите планировщик на верхнем уровне (например, dm-0)
echo mq-deadline | sudo tee /sys/block/dm-0/queue/scheduler

# Базовые устройства NVMe/SAS "нет", чтобы избежать двойного планирования
for d in /sys/block/nvme*n1 /sys/block/sd*; do echo none | sudo tee $d/queue/scheduler; done

# mdraid: оптимизация readahead и stripe cache (RAID5/6)
sudo blockdev --setra 4096 /dev/md0
echo 4096 | sudo tee /sys/block/md0/md/stripe_cache_size

При работе с зашифрованными томами (dm-crypt/LUKS) я обращаю внимание на разгрузку процессора (AES-NI) и убеждаюсь, что путь ввода-вывода не блуждает по рабочим очередям без необходимости. Я специально измеряю задержки синхронизации-записи, поскольку они могут увеличиваться из-за криптоуровня. В многоканальных средах (SAN/iSCSI) я настраиваю планировщик на многоканальном устройстве (dm-X) и проверяю, чтобы обход отказа пути не приводил к выбросам.

Виртуализация и контейнеры: хост и гость

В стеке KVM я намеренно разделяю хост и гостя. В Гость Обычно я использую для устройств virtio нет, чтобы гипервизор взял на себя оптимизацию. На Хозяин Затем я выбираю планировщик для каждого физического устройства, который соответствует аппаратному обеспечению (часто none/mq-deadline на SSD/NVMe).

# Guest (virtio-blk/virtio-scsi): Установите для планировщика значение "none
echo none | sudo tee /sys/block/vda/queue/scheduler

Хост #: QEMU с iothreads и multiqueue для virtio-blk
qemu-system-x86_64 \
  -drive if=none,id=vd0,file=/var/lib/libvirt/images/guest.qcow2,cache=none,aio=native \
  -объект iothread,id=ioth0 \
  -device virtio-blk-pci,drive=vd0,num-queues=8,iothread=ioth0

Я привязываю контейнеры непосредственно к Cgroups v2 и использую свойства systemd (IOWeight, IOReadBandwidthMax/IOWriteBandwidthMax), чтобы службы автоматически запускались с правильными бюджетами ввода-вывода. Важно: Во избежание конфликтующих правил устанавливайте приоритеты только на одном уровне - либо в контейнере, либо в хост-службе.

Оптимизация NUMA, IRQ и опроса

В многосокетных системах я рассматриваю ввод-вывод и процессор. Близко к NUMA. Я проверяю распределение прерываний NVMe и при необходимости корректирую их, если irqbalance работает неоптимально. Я также использую опции blk-mq, чтобы сохранить локальность завершений.

# Проверьте прерывания NVMe и установите маски ядра (пример)
grep -i nvme /proc/interrupts
echo  | sudo tee /proc/irq//smp_affinity

# blk-mq: Завершения на генерирующем ядре
echo 2 | sudo tee /sys/block//queue/rq_affinity

# Дополнительно: тестирование опроса ввода-вывода в зависимости от рабочей нагрузки (используйте осторожно)
echo 0 | sudo tee /sys/block//queue/io_poll

Для NVMe я могу использовать функции контроллера для настройки параметров коалесцирования прерываний, чтобы сгладить соотношение загрузки процессора и задержки. Я делаю небольшие шаги и проверяю, остается ли P99 стабильным или коалесценция приводит к заметной медлительности.

Образцы профилей должностей в фио и план измерений

Я создаю воспроизводимые файлы заданий и записываю параметры ядра, планировщика, очереди и монтирования файловой системы. Это позволяет мне сравнивать результаты в течение нескольких недель.

# db-sync.fio - синхронная запись с DB-подобными файлами (ext4/XFS)
[global]
ioengine=libaio
прямой=1
filename=/dev/
основанный на времени=1
время выполнения=90
поток=1
numjobs=8
iodepth=1

[randwrite-sync4k].
rw=randwrite
bs=4k
fsync=1

# web-randread.fio - Web-подобные чтения
[global]
ioengine=libaio
прямой=1
имя файла=/dev/
основанный на времени=1
время выполнения=90
поток=1
numjobs=8
iodepth=32

[randread-4k]
rw=randread
bs=4k
# Измерительная рамка
# 1) Разминка 60 с, 2) Измерение 90 с, 3) Остывание 30 с
# Параллельно: запустите iostat, pidstat и blktrace

iostat -x 1 | tee iostat.log &
pidstat -dl 1 | tee pidstat.log &
blktrace -d /dev/ -o - | blkparse -i - -d trace.dump &

Трассировка #: извлечение P95/P99 из fio-JSON
fio --output-format=json --output=fio.json db-sync.fio
jq '.jobs[].lat_ns["percentile"]|{p95:.["95.000000"],p99:.["99.000000"]}' fio.json

Я изменяю только одну переменную, например планировщик или read_ahead_kb, и снова сравниваю идентичные файлы заданий. И только когда улучшения становятся одинаковыми в течение нескольких запусков, я фиксирую настройки.

Управление изменениями: безопасное внедрение и откат

В продуктивных средах хостинга я внедряю изменения ввода-вывода ступенчатый Я начинаю с хоста canary, затем небольшой партии AZ/кластера и только потом - широкое распространение. Я верстаю правила Udev и прикрепляю каждое изменение к тикету с измеренными значениями. Для отката у меня есть готовый сценарий, который воспроизводит предыдущие значения (планировщик, read_ahead_kb, лимиты Cgroup). Таким образом, вмешательства остаются обратимыми, если рабочая нагрузка меняется в кратчайшие сроки.

Краткое содержание: Вот как я действую

Я начинаю с четкого Фактическое значение, Я измеряю задержки и пропускную способность и документирую настройку. Затем я выбираю подходящий планировщик для каждого устройства: none для NVMe/виртуальных SSD, mq-deadline для смешанных серверных нагрузок, BFQ для общих сред с большим количеством пользователей. Затем я настраиваю readahead, RQ affinity и приоритеты процессов, чтобы определить приоритетность внешних рабочих нагрузок. Если измерения постоянно показывают, что выбор работает, я исправляю его через udev/GRUB и записываю параметры. Мониторинг остается активным, поскольку рабочие нагрузки меняются, и с помощью небольших исправлений я сохраняю Производительность постоянно высокий.

Текущие статьи

Сервер с оптимизированным планировщиком ввода-вывода ядра для хостинга
Серверы и виртуальные машины

Настройка планировщика ввода-вывода ядра: оптимизация для повышения производительности хостинга

Kernel I/O Scheduler Tuning оптимизирует планирование дисков Linux для максимальной производительности хостинга. Советы для Noop, mq-deadline и BFQ.

SSD-накопители в хостинговом центре обработки данных с визуализацией потоков данных
Серверы и виртуальные машины

Усиление записи на SSD в режиме хостинга: оптимизация для увеличения срока службы хранилища и повышения производительности

SSD Write Amplification: как минимизировать износ хранилища и производительность диска в средах хостинга. Узнайте об оптимизации WAF и корпоративных стратегиях.

Предварительная выборка и предварительная загрузка DNS для ускорения загрузки веб-сайта
веб-хостинг

Предварительная выборка и предварительная загрузка DNS: оптимизация скорости веб-сайта

Предварительная выборка и предварительная загрузка DNS оптимизируют **скорость веб-сайта** за счет раннего разрешения DNS и предварительной загрузки ресурсов. Идеально подходит для веб-хостинга.