Периодически то тут, то там возникают вопросы о рекомендациях Gluster относительно настройки ядра и есть ли в этом необходимость.
Такая необходимость возникает редко. На большинстве нагрузок ядро работает очень хорошо. Хотя есть и обратная сторона. Исторически ядро Linux охотно потребляет много памяти, если ему предоставить такую возможность, в том числе и для кэширования в качестве основного способа повышения производительности.
В большинстве случаев это работает отлично, но при большой нагрузке может привести к проблемам.
У нас есть большой опыт работы с системами, потребляющими много памяти, такими как, CAD, EDA и подобными, которые начинали тормозить при высокой нагрузке. И иногда мы сталкивались с проблемами в Gluster. Тщательно понаблюдав не один день за используемой памятью и временем ожидания дисков мы получили их перегрузку, огромные iowait, ошибки ядра (kernel oops), зависания и т.п.
Эта статья является результатом многих экспериментов по настройке параметров, выполненных в различных ситуациях. Благодаря этим параметрам не только улучшилась отзывчивость в целом, но и значительно стабилизировалась работа кластера.
Когда дело доходит до настройки памяти, то первым делом надо смотреть на подсистему виртуальной памяти (VM, virtual memory), у которой есть большое количество опций, способных ввести вас в замешательство.
vm.swappiness
Параметр vm.swappiness определяет насколько ядро использует свопинг (swap, подкачку) по сравнению с оперативной памятью. В исходном коде он также определен как «tendency to steal mapped memory» (склонность к краже отображаемой памяти). Высокое значение swappiness означает, что ядро будет более склонно к выгрузке отображенных страниц. Низкое значение swappiness означает обратное: ядро будет меньше выгружать страницы из памяти. Другими словами, чем выше значение vm.swappiness, тем больше система будет использовать swap.
Большое использование свопинга нежелательно, так как в оперативную память загружаются и выгружаются огромные блоки данных. Многие утверждают, что значение swapiness должно быть большим, но по моему опыту, к увеличению производительности приводит установка в «0».
Но, опять же, эти настройки должны применяться с осторожностью и только после тестирования конкретного приложения. Для высоконагруженных потоковых приложений этот параметр следует устанавливать в «0». При изменении на «0» отзывчивость системы улучшается.
vm.vfs_cache_pressure
Этот параметр контролирует память, потребляемую ядром для кэширования объектов каталогов и индексных дескрипторов (dentry и inode).
При значении по умолчанию в 100 ядро будет пытаться освобождать кэш dentry и inode по «справедливости» по отношению к pagecache и swapcache. Уменьшение vfs_cache_pressure приводит к тому, что ядро будет сохранять кэши dentry и inode. Когда значение равно «0», ядро никогда не будет очищать кэш dentry и inode из-за нехватки памяти (memory pressure), и это может легко привести к ошибке out-of-memory. Увеличение vfs_cache_pressure больше 100 приводит к тому, что ядро отдает приоритет выгрузке dentry и inode.
При использовании GlusterFS много пользователей с большими объемами данных и множеством маленьких файлов легко могут использовать на сервере значительное количество оперативной памяти из-за кэширования inode/dentry, что может привести к снижению производительности, так как ядру приходится обрабатывать структуры данных в системе с 40 ГБ памяти. Установка этого параметра больше 100 помогла многим пользователям добиться более справедливого кэширования и улучшить отзывчивость ядра.
vm.dirty_background_ratio и vm.dirty_ratio
Первый параметр (vm.dirty_background_ratio) определяет процент памяти с грязными страницами, достигнув который необходимо начать фоновый сброс грязных страниц на диск. Пока этот процент не достигнут, страницы не сбрасываются на диск. А когда сброс начинается, он выполняется в фоновом режиме, не прерывая работающие процессы.
Второй параметр (vm.dirty_ratio) определяет процент памяти, который может быть занят грязными страницами до начала принудительного сброса (forced flash). При достижении этого порога все процессы становятся синхронными (блокируются), и им не разрешается продолжать работу до тех пор, пока запрошенная ими операция ввода-вывода не будет фактически завершена и данные не окажутся на диске. При высоконагруженном вводе-выводе это вызывает проблему, так как кэширование данных отсутствует, и все процессы, выполняющие ввод-вывод, блокируются в ожидании ввода-вывода. Это приводит к большому количеству зависших процессов, высокой нагрузке, нестабильной работе системы и плохой производительности.
Уменьшение значений этих параметров приводит к тому, что данные чаще сбрасываются на диск и не хранятся в ОЗУ. Это может помочь системам с большим количеством памяти, для которых нормально сбрасывать на диск кэш страниц размером 45–90 ГБ, что приводит к огромному времени ожидания для фронтенд-приложений, снижая общую отзывчивость и интерактивность.
«1» > /proc/sys/vm/pagecache
Страничный кэш (page cache) — это кэш, в котором хранятся данные файлов и исполняемых программ, то есть это страницы с фактическим содержимым файлов или блочных устройств. Этот кэш используется для уменьшения количества чтений с диска. Значение «1» означает, что для кэша используется 1% ОЗУ и операций чтения с диска будет больше, чем из ОЗУ. Изменять этот параметр не обязательно, но если вы параноидально относитесь к контролю над кэшем страниц, то можете им воспользоваться.
«deadline» > /sys/block/sdc/queue/scheduler
Планировщик ввода-вывода (I/O scheduler) — это компонент ядра Linux, который обрабатывает очереди чтения и записи. Теоретически для умного RAID-контроллера лучше использовать «noop», потому что Linux ничего не знает о физической геометрии диска, поэтому эффективнее позволить контроллеру, хорошо знающему геометрию диска, как можно быстрее обработать запрос. Но похоже, что «deadline» повышает производительность. Подробнее о планировщиках можно прочитать в документации к исходному коду ядра Linux: linux/Documentation/block/*osched.txt. И также я наблюдал увеличение пропускной способности чтения во время смешанных операций (много операций записи).
«256» > /sys/block/sdc/queue/nr_requests
Количество запросов ввода-вывода в буфере перед тем как они передаются планировщику. Размер внутренней очереди некоторых контроллеров (queue_depth) больше, чем nr_requests планировщика ввода-вывода, так что у планировщика ввода-вывода мало шансов правильно приоритезировать и выполнить слияние запросов. Для планировщиков deadline и CFQ лучше, когда nr_requests в 2 раза больше внутренней очереди контроллера. Объединение и переупорядочивание запросов помогает планировщику быть более отзывчивым при большой нагрузке.
echo «16» > /proc/sys/vm/page-cluster
Параметр page-cluster управляет количеством страниц, которые записываются в своп за один раз. В приведенном выше примере значение устанавливается равным «16» в соответствии с размером страйпа (stripe size) RAID в 64 КБ. Это не имеет смысла при swappiness = 0, но если вы установили swappiness в 10 или 20, то использование этого значения поможет вам, когда размер страйпа RAID составляет 64 КБ.
blockdev —setra 4096 /dev/<devname> (-sdb, hdc или dev_mapper)
Настройки блочных устройств по умолчанию для многих RAID-контроллеров часто приводят к ужасной производительности. Добавление вышеуказанной опции, настраивает упреждающее чтение для 4096 * 512-байтных секторов. По крайней мере, для потоковых операций увеличивается скорость, наполняя встроенный кэш диска за счет упреждающего чтения в течение периода, используемого ядром для подготовки ввода-вывода. В кэш могут помещаться данные, которые будут запрошены при следующем чтении. Слишком большое упреждающее чтение может убить случайный ввод-вывод для больших файлов, если он использует потенциально полезное время диска или загружает данные за пределами кэша.
Ниже приведены еще несколько рекомендаций на уровне файловой системы. Но они еще не были протестированы. Убедитесь, что ваша файловая система знает размер страйпа и количество дисков в массиве. Например, что это массив raid5 с размером страйпа 64K из шести дисков (фактически из пяти, потому что один диск используется для четности). Эти рекомендации основаны на теоретических предположениях и собраны из различных блогов/статей экспертов по RAID.
-> ext4 fs, 5 disks, 64K stripe, units in 4K blocks
mkfs -text4 -E stride=$((64/4))
-> xfs, 5 disks, 64K stripe, units in 512-byte sectors
mkfs -txfs -d sunit=$((64*2)) -d swidth=$((5*64*2))
Для больших файлов можно рассмотреть возможность увеличения указанных выше размеров страйпов.
ВНИМАНИЕ! Все, что описано выше крайне субъективно для некоторых типов приложений. Эта статья не гарантирует какие-либо улучшения без предварительного тестирования соответствующих приложений со стороны пользователя. Ее следует применять только в случае необходимости улучшения общей отзывчивости системы или, если она решает текущие проблемы.