Как стать автором
Обновить
0
Интернет Контроль Сервер
Универсальный инструмент системного администратора

Погружение в работу SWAP ОС FreeBSD

Время на прочтение9 мин
Количество просмотров4.4K
Автор оригинала: Mark Johnston

Приветствуем всех пользователей и интересующихся FreeBSD. Как известно, в основе нашего продукта, Интернет Контроль Сервер, лежит данная ОС. Поэтому, мы не могли обойти стороной вопрос SWAP и рады поделиться переводом полезной статьи.

Свободная память = память, потраченная впустую? Как использовать swap наилучшим образом.

Для современных Unix-систем, таких как FreeBSD, термин “swapping” (подкачка памяти) означает операции по выгрузке данных из памяти на диск (устройство подкачки) и обратно, осуществляемые по требованию. 

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

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

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

Описанная технология выглядит весьма рациональной. Объем памяти дисков обычно больше объема RAM, так почему бы не использовать их для кэширования редко используемых страниц памяти? Однако, для многих опытных администраторов процесс подкачки памяти до сих пор воспринимается как некорректное поведение системы. И этому есть объяснение: до недавнего времени диски, используемые для подкачки памяти, имели задержки доступа в миллионы раз выше, чем у RAM.

Как правило, время ожидания доступа к данным, сохраненным на устройстве подкачки, составляет порядка нескольких десятков миллисекунд, тогда как доступ к RAM занимает десятки наносекунд. Таким образом, активное использование процесса выгрузки данных может снизить производительность системы, из-за чего это воспринимается как признак нехватки RAM или означает необходимость оптимизации использования памяти. Распространенным решением является полное отключение подкачки памяти, что вынуждает ОС при необходимости прибегать к другим способам освобождения памяти.

В 2021 году получили распространение недорогие SSD-диски, производительность которых подходит для процесса подкачки памяти. Поэтому стоит пересмотреть процесс подкачки памяти во FreeBSD и изучить часто возникающие проблемы.

Подкачка памяти: когда и как много?

Компьютерные системы имеют фиксированное количество RAM. Оптимизация её использования ложится на плечи операционной системы. 

Было бы идеально, если ОС могли бы заглядывать в будущее, чтобы спрогнозировать какие данные будут запрошены и, имея такую информацию, гарантировать доступ к этим данным в RAM до выполнения запроса.

В реальности, для определения возможных запросов к данным памяти ОС используют эвристические алгоритмы.

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

Если нет доступной свободной памяти и приложение запрашивает не кэшированные данные, FreeBSD определяет к какому разделу памяти обращались реже всего за последнее время и удаляет его содержимое, чтобы освободить место для новых данных. Данный алгоритм называется Least-Recently Used (LRU).

При этом ядро не может просто удалить данные : если их копии нет на диске, то данные сперва должны быть выгружены на диск.

Таким образом процесс подкачки памяти тесно связан с LRU.

Точное выполнение алгоритма LRU сопровождается большим количеством избыточной работы, поэтому FreeBSD реализует вариант, приближенный к LRU: ОС пытается найти разделы памяти, к которым не обращались долгое время, и выселяет их.

Как часть этой реализации, FreeBSD разбивает системную память на набор очередей: active, inactive и laundry очереди . Размер каждой из этих очередей отображается утилитой top(1):

Mem: 2591M Active, 6576M Inact, 1389M Laundry, 4155M Wired, 1543M Buf, 1130M Free
Swap: 8192M Total, 1623M Used, 6569M Free, 19% Inuse

Страницы памяти “Wired” не могут быть выгружены на диск, поэтому они не задействованы в реализации алгоритма LRU. Страницы памяти в очереди active (поле “Active” в выводе top) - это память, к которой часто обращаются; обычно они отображаются в одно или несколько адресных пространств процессов. Например, память, возвращаемая malloc будет изначально находиться в очереди active. Чтобы определить, к каким из страниц очереди active давно не обращались, ядро системы периодически запускает процесс под названием “page daemon”, который изучает историю обращений к каждой странице памяти за последнее время. Страницы памяти к которым не обращаются, перемещаются из очереди active в очередь inactive.

Очередь inactive содержит страницы памяти, к которым не было запросов за последнее время. Если ядру потребуется решить проблему нехватки свободной памяти, такие страницы являются подходящим вариантом для повторного использования. Данная очередь позволяет упорядочить страницы по давности обращения к ним: новые страницы помещаются в конец очереди, а для восстановления используются страницы из начала очереди.

Ранее мы отметили, что корректно работающие ОС не должны удалять данные для решения проблемы нехватки памяти. Если страница памяти содержит данные, копии которых нет в хранилище, то она отмечается как “грязная”, и перед ее использованием необходимо выгрузить данные в хранилище. В ином случае страница является “чистой”. 

Например, если кто-то выполняет поиск файла используя grep(1), данные этого файла должны быть загружены в память, но из-за того, что grep(1) просто считывает эти данные, страница памяти будет отмечена как “чистая” и может быть использована повторно в любой момент.

Очереди active и inactive будут содержать и грязные и чистые страницы памяти. Процесс “page daemon” освобождает чистые страницы из начала очереди inactive для решения проблемы нехватки памяти. Грязные страницы памяти сперва должны быть очищены путем выгрузки на устройство подкачки или на файловую систему. 

Это большой объём работы, поэтому page daemon перемещает их в очередь laundry для отложенной обработки. Очередь laundry управляется отдельным потоком laundry thread, который решает когда и какой объем памяти необходимо выгрузить. Связь между этими очередями изображена на картинке:

Суммируем вышесказанное:

  • процесс “page daemon” переносит страницы памяти, к которым больше нет обращений, из очереди active в очередь inactive (1).

  • для освобождения памяти, процесс “page daemon” сканирует страницы памяти в начале очереди inactive (2), освобождает чистые страницы (6) и переносит грязные в конец очереди laundry (3).

  • когда поток laundry thread решает очистить некоторые грязные страницы (4), он передает их в swap pager, который записывает содержимое страниц в стабильное хранилище и затем помещает очищенные страницы памяти в очередь inactive (5).

  • если к странице памяти обращаются после того, как она была помещена в очередь inactive или laundry, она будет постепенно перемещена обратно в очередь active

Одна из возможных стратегий работы потока laundry thread - оставаться неактивным, ожидая восстановления чистых страниц памяти, что удовлетворит потребность в свободной памяти. В действительности это именно то, что происходит при полном отключении опции подкачки памяти. Однако, по умолчанию, страницы памяти в очереди laundry неактивны, а неиспользуемая память является потраченной впустую. Другой стратегией является “отстирывание” страниц памяти как только они попадают в очередь, но это может привести к нежелательному I/O.

Политика потока laundry thread использует несколько параметров:

  1. показатель длины очередей inactive и laundry

  2. количество чистых страниц, восстановленных с момента последней выгрузки на диск

  3. длина очереди inactive относительно ее целевого (минимального) размера

Поток laundry thread использует первые два параметра для контроля процесса “отстирывания” страниц в фоновом режиме, в то время как третий параметр используется для “отстирывания” страниц в условиях дефицита памяти.

Идея “отстирывания” в фоновом режиме состоит в попытке убедиться, что часть грязных страниц выгружаются на диск до того, как возникнет нехватка чистых страниц в очереди inactive. Когда в системе заканчиваются и свободные страницы, и очищенные страницы из очереди inactive, приложения, которым требуется свободная память, переходят в режим ожидания выгрузки новых страниц. 

При этом поток laundry thread пытается избежать увеличения очереди laundry: чем больше соотношение (1) размера очередей, тем чаще поток laundry thread будет выполнять выгрузку грязных страниц памяти. 

Поскольку выгрузка данных грязных страниц при наличии достаточного объема свободной памяти приводит к снижению пропускной способности I/O, поток laundry thread контролирует активность процесса page daemon с целью определения оптимальной частоты выгрузки памяти.

Почему моя система использует так много пространства swap?

Когда данные грязной страницы загружаются на устройство подкачки, страница отмечается как чистая и может быть использована заново. На этом этапе, содержимое страницы в точности совпадает с копией, созданной на устройстве подкачки. (Страница может быть снова помечена как грязная и возвращена в очередь active в случае, если недавно к ней были обращения). 

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

Для некоторых типов данных может быть характерен шаблон доступа «единоразовая запись, многоразовое чтение». Например, продолжительные по времени процессы могут выделять область памяти и производить на нее запись во время запуска, а затем, только считывать данные из этого раздела памяти. Если данные памяти выгружаются, FreeBSD будет сохранять их копию на устройстве подкачки до тех пор, пока эта копия остается актуальной. В противном случае (прим: если бы копия не сохранялась на весь период времени пока она актуальна) пришлось бы выполнить другую дорогостоящую операцию выгрузки данных на устройство подкачки, чтобы восстановить для нового использования данные этой памяти.

Примечание: если память попала в очередь inactive, а копия на устройстве подкачки была затерта, то, соответственно, память помечается грязной, и для переиспользования этой памяти нужно её очистить, т.е. заново выгрузить содержимое на устройство подкачки.

Таким образом, обычно наблюдается умеренное использование пространства подкачки даже при наличии большого объема свободной памяти : в какой-то момент в прошлом потребность в свободной памяти вызвала выгрузку данных на устройство подкачки, и выгруженные данные остаются действительными.

Почему ядро останавливает мои процессы?

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

Поток laundry thread может выгружать данные памяти так быстро, как это возможно, но это может не удовлетворять требованиям системы, или устройство подкачки может быть полным. В этот момент ядру ничего не остаётся кроме, как попытаться остановить процесс, чтобы вернуть память и восстановить стабильность системы - этот метод носит название OOM (out-of-memory) kill.

FreeBSD инициирует запуск OOM kill в паре случаев. Первый случай: если процесс page daemon несколько раз не может восстановить страницы из очереди inactive. Второй случай: если устройство подкачки полное, поток laundry thread не способен перемещать страницы из очереди laundry в очередь inactive. Эти состояния могут привести к OOM kill, что освободит некоторое место на устройстве подкачки.

FreeBSD также инициирует OOM kill, если обнаружит, что поток застрял в обработчике отказа страниц (page fault). Обработка отказа страниц требует выделения некоторого объёма памяти и, если приложения терпят неудачу в процессе этой операции, то ядро начинает остановку процессов. 

Это помогает выявить ситуации, когда медленно движущаяся очередь восстанавливаемых страниц препятствует запуску эвристического алгоритма, но система при этом не отвечает.

Чтобы найти процесс для остановки, ядро оценивает использование памяти каждым запущенным процессом и выделяет один с самым большим использованием. Эта эвристика работает хорошо, когда OOM kill был инициирован в результате утечки памяти в пространстве пользователя (user-space), так как она идентифицирует процессы с утекающей памятью. 

Однако, процесс, который нужно остановить, может быть заблокирован, так что его остановка не освободит память мгновенно. В этой ситуации ядро может выполнять несколько OOM kill один за другим, что в итоге приведёт к остановке важных системных процессов.

Привилегированные процессы могут запросить иммунитет от OOM kill парой способов:

  1. Код процесса может использовать madvise(MADV_PROTECT), чтобы OOM kill не выбирал этот процесс. Эта защита не распространяется на дочерние процессы. Многие основные службы в базовой системе FreeBSD, такие как syslogd и sshd, используют этот метод.

  2. Программа protect(1) может быть использована, чтобы запустить процесс с защитой от OOM. Если сервис запускается через rc, то защита может быть установлена через переменную ${name}_oomprotect=YES в файле rc.conf.

Следует ли мне включать подкачку?

Однозначного ответа на этот вопрос нет. 

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

В версиях FreeBSD до 11.0, процесс page daemon отвечал и за освобождение чистых inactive страниц и за отстирывание грязных inactive страниц, поэтому большое число операций подкачки могло тормозить операции восстановления памяти и вызывать зависания.

Многие системные администраторы против включения подкачки из-за риска неограниченной задержки в работе приложений, вызванной чрезмерной подкачкой. Во многом это связано с опытом использования медленных жестких дисков в качестве устройств подкачки, особенно при совместном использовании с загруженной файловой системой. 

Мы считаем, что единомышленникам FreeBSD стоит попробовать снова включить подкачку. Накопители NVMe - обычное дело и имеют задержки доступа в десятки микросекунд, что на несколько порядков меньше, чем стандартные диски десятилетней давности. 

Производительность FreeBSD в условиях нехватки памяти продолжает улучшаться, а ядро постоянно подвергается  стресс-тестам. Для приложений, особенно чувствительные к задержке доступа к памяти, можно использовать mlock, в то время как система в целом может выиграть от повышения эффективности памяти, которую обеспечит подкачка.

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

Теги:
Хабы:
+4
Комментарии3

Публикации

Информация

Сайт
xserver.a-real.ru
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия

Истории