Что такое sysctl vm.min_free_kbytes, настраиваемый для ядра Linux, и какое значение должно быть установлено? В этой статье мы изучим этот параметр и его влияние на работающую систему Linux. Мы проверим его влияние на кэш страниц ОС и на маллоки, а также на то, что показывает команда system free при установке этого параметра. Мы сделаем несколько обоснованных предположений об идеальных значениях для этого параметра и покажем, как установить vm.min_free_kbytes на постоянной основе, чтобы выдержать перезагрузку. Итак, начнем.
Выделение памяти может потребоваться системе для обеспечения правильного функционирования самой системы. Если ядро позволяет выделить всю память, оно может столкнуться с трудностями при потребности в памяти для регулярных операций, чтобы обеспечить бесперебойную работу ОС. Вот почему ядро предоставляет настраиваемый vm.min_free_kbytes. Настраиваемый параметр заставит диспетчер памяти ядра сохранить не менее X объема свободной памяти. Вот официальное определение из документации ядра Linux: «Это используется для того, чтобы заставить виртуальную машину Linux сохранять минимальное количество килобайт свободным. ВМ использует это число для вычисления значения водяного знака [WMARK_MIN] для каждой зоны lowmem в системе. Каждая зона lowmem получает количество зарезервированных бесплатных страниц пропорционально ее размеру. Некоторый минимальный объем памяти необходим для распределения PF_MEMALLOC; если вы установите это значение ниже 1024 КБ, ваша система станет незаметно сломанной и склонной к тупиковой ситуации при высоких нагрузках. Установка слишком большого значения мгновенно отключит вашу машину».
Чтобы проверить, что настройка min_free_kbytes работает так, как задумано, я создал виртуальный экземпляр Linux только с 3,75 ГБ ОЗУ. Используйте бесплатную команду ниже для анализа системы:
# free -m
Рассмотрим приведенную выше утилиту для свободной памяти с использованием флага -m для вывода значений в МБ. Общий объем памяти составляет от 3,5 до 3,75 ГБ. Используется 121 МБ памяти, свободно 3,3 ГБ, буферный кеш занимает 251 МБ. И доступно 3,3 ГБ памяти.
Теперь мы собираемся изменить значение vm.min_free_kbytes и посмотреть, как это отразится на системной памяти. Мы выведем новое значение в виртуальную файловую систему proc, чтобы изменить значение параметра ядра, как показано ниже:
# echo 1500000 > /proc/sys/vm/min_free_kbytes # sysctl vm.min_free_kbytes
Видно, что параметр был изменен примерно на 1,5 ГБ и вступил в силу. Теперь давайте снова воспользуемся командой free, чтобы увидеть любые изменения, распознаваемые системой.
# free -m
Свободная память и буферный кеш не изменяются командой, но объем памяти, отображаемый как доступный, был уменьшен с 3327 до 1222 МБ. Что примерно соответствует уменьшению изменения параметра до 1,5 ГБ мин свободной памяти.
Теперь давайте создадим файл данных размером 2 ГБ, а затем посмотрим, что чтение этого файла в буферный кеш делает со значениями. Вот как создать файл данных размером 2 ГБ в двух строках сценария bash ниже. Сценарий сгенерирует случайный файл размером 35 МБ с помощью команды dd, а затем скопирует его 70 раз в новый вывод data_file :
# dd if=/dev/random of=/root/d1.txt count=1000000 # for i in `seq 1 70`; do echo $i; cat /root/d1.txt >> /root/data_file; done
Давайте прочитаем файл и проигнорируем его содержимое, прочитав и перенаправив файл в /dev/null, как показано ниже:
# cat data_file > /dev/null
Хорошо, что случилось с нашей системной памятью с помощью этого набора маневров, давайте сейчас это проверим:
# free -m
Анализируя результаты выше. У нас все еще есть 1,8 ГБ свободной памяти, поэтому ядро защитило большой кусок памяти как зарезервированный из-за нашей настройки min_free_kbytes. Буферный кеш использовал 1691 МБ, что меньше, чем общий размер нашего файла данных, который составляет 2,3 ГБ. Очевидно, весь файл data_file не может быть сохранен в кеше из-за отсутствия доступной памяти для использования для буферного кеша. Мы можем проверить, что весь файл не хранится в кеше, но рассчитываем время повторных попыток чтения файла. Если он был кэширован, чтение файла заняло бы долю секунды. Давай попробуем.
# time cat data_file > /dev/null # time cat data_file > /dev/null
Чтение файла заняло почти 20 секунд, что означает, что он почти наверняка не кэшируется.
В качестве последней проверки давайте уменьшим vm.min_free_kbytes, чтобы у кэша страницы было больше места для работы, и мы можем ожидать, что кеш будет работать, а чтение файла станет намного быстрее.
# echo 67584 > /proc/sys/vm/min_free_kbytes # time cat data_file > /dev/null # time cat data_file > /dev/null
С дополнительной памятью, доступной для кэширования, время чтения файла упало с 20 секунд до 0,364 секунды, когда все это было в кеше.
Мне любопытно провести еще один эксперимент. Что происходит с вызовами malloc для выделения памяти из программы на языке C при очень высоком значении vm.min_free_kbytes. Не справится ли он с malloc? Система умрет? Сначала сбросьте параметр vm.min_free_kbytes на действительно высокое значение, чтобы возобновить наши эксперименты:
# echo 1500000 > /proc/sys/vm/min_free_kbytes
Теоретически у нас свободно 1,9 ГБ и доступно 515 МБ. Давайте воспользуемся программой стресс-теста под названием stress-ng, чтобы задействовать немного памяти и посмотреть, где мы потерпим неудачу. Мы воспользуемся vm tester и попробуем выделить 1 ГБ памяти. Поскольку мы зарезервировали только 1,5 ГБ в системе 3,75 ГБ, мы думаем, это должно сработать.
# stress-ng --vm 1 --vm-bytes 1G --timeout 60s stress-ng: info: [17537] dispatching hogs: 1 vm stress-ng: info: [17537] cache allocate: default cache size: 46080K stress-ng: info: [17537] successful run completed in 60.09s (1 min, 0.09 secs) # stress-ng --vm 2 --vm-bytes 1G --timeout 60s # stress-ng --vm 3 --vm-bytes 1G --timeout 60s
Давайте попробуем еще раз с большим количеством воркеров, мы можем попробовать 1, 2, 3, 4 воркера, и в какой-то момент он должен потерпеть неудачу. В нашем тесте он прошел с 1 и 2 рабочими, но не прошел с 3 рабочими.
Давайте сбросим vm.min_free_kbytes на меньшее значение и посмотрим, поможет ли это нам запустить 3 фактора стресса памяти по 1 ГБ каждый в системе 3,75 ГБ.
# echo 67584 > /proc/sys/vm/min_free_kbytes # stress-ng --vm 3 --vm-bytes 1G --timeout 60s
На этот раз все прошло успешно, без ошибок, мы пробовали два раза без проблем. Таким образом, мы можем сделать вывод, что существует различие в поведении, заключающееся в наличии большего объема памяти для malloc, когда для значения vm.min_free_kbytes установлено более низкое значение.
Значение по умолчанию для параметра в моей системе — 67584, что составляет около 1,8% ОЗУ в системе или 64 МБ. По соображениям безопасности на сильно перегруженной системе я бы увеличил его немного, возможно, до 128 МБ, чтобы учесть больше зарезервированной свободной памяти, однако для среднего использования значение по умолчанию кажется достаточно разумным. Официальная документация предупреждает о завышении значения. Установка 5 или 10% системной ОЗУ, вероятно, не является предполагаемым использованием параметра и слишком высока.
Чтобы гарантировать, что параметр может выдерживать перезагрузку и не восстанавливается до значений по умолчанию при перезагрузке, обязательно сделайте параметр sysctl постоянным, поместив желаемое новое значение в файл /etc/sysctl.conf.
Мы видели, что настраиваемый параметр ядра Linux vm.min_free_kbytes может быть изменен и может резервировать память в системе, чтобы обеспечить более стабильную работу системы, особенно при интенсивном использовании и интенсивном распределении памяти. Настройки по умолчанию могут быть слишком низкими, особенно в системах с большим объемом памяти, и их следует тщательно увеличивать. Мы видели, что память, зарезервированная этим параметром, не позволяет кешу ОС использовать всю память, а также предотвращает использование всей памяти некоторыми операциями malloc.
«Используйте бесплатную команду ниже для анализа системы» — а если в моём дистрибутиве она попросит денег? В-)