Русский
Русский
English
Статистика
Реклама

Почему линукс использует swap-файл, часть 2

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

Поэтому, сегодня мы сделаем Крошечную лабораторную работу. В виде крошечной же программы на C, которую мы напишем, скомпилируем и проверим в деле со свапом и без свапа.

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

А вызов кода из этой библиотеки мы просто эмулируем чтением из такого mmap-нутого файла.

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

И, чтобы не писать лишнего кода, мы определим две константы, которые определят размер сегмента кода и общий размер оперативной памяти:

  • MEM_GBYTES размер оперативной памяти для теста
  • LIB_GBYTES размер кода

Объем данных у нас меньше объема физической памяти:

  • DATA_GBYTES = MEM_GBYTES 2

Суммарный объем кода и данных чуть больше объема физической памяти:

  • DATA_GBYTES + LIB_GBYTES = MEM_GBYTES + 1

Для теста на ноутбуке я взял MEM_GBYTES = 16, и получил следующие характеристики:

  • MEM_GBYTES = 16
  • DATA_GBYTES = 14 значит данных будет 14GB, то есть памяти достаточно
  • Swap size = 16GB

Текст программы


#include <sys/mman.h>#include <fcntl.h>#include <string.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#define GB       1073741824l#define MEM_SIZE    16#define LIB_GBYTES   3#define DATA_GBYTES   (MEM_SIZE - 2)long random_read(char * code_ptr, char * data_ptr, size_t size) {long rbt = 0;for (unsigned long i=0 ; i<size ; i+=4096) {rbt += code_ptr[(8l * random() % size)] + data_ptr[i];}return rbt;}int main() {size_t libsize = LIB_GBYTES * GB;size_t datasize = DATA_GBYTES * GB;int fd;char * dataptr;char * libptr;srandom(256);if ((fd = open("library.bin", O_RDONLY)) < 0) {printf("Required library.bin of size %ld\n", libsize);return 1;}if ((libptr = mmap(NULL, libsize,PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {printf("Failed build libptr due %d\n", errno);return 1;}if ((dataptr = mmap(NULL, datasize,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,-1, 0)) == MAP_FAILED) {printf("Failed build dataptr due %d\n", errno);return 1;}printf("Preparing test ...\n");memset(dataptr, 0, datasize);printf("Doing test ...\n");unsigned long chunk_size = GB;unsigned long chunk_count = (DATA_GBYTES - 3) * GB / chunk_size;for (unsigned long chunk=0 ; chunk < chunk_count; chunk++) {printf("Iteration %d of %d\n", 1 + chunk, chunk_count);random_read(libptr, dataptr + (chunk * chunk_size), libsize);}return 0;}

Тест без использования swap


Запрещаем swap указав vm.swappines=0 и запускаем тест
$ time ./swapdemoPreparing test ...Killedreal 0m6,279suser 0m0,459ssys 0m5,791s


Что произошло? Значение swappiness=0 отключило свап анонимные страницы в него больше не вытесняются, то есть данные всегда в памяти. Проблема в том, что оставшихся 2GB не хватило для работающих в фоне Chrome и VSCode, и OOM-killer убил тестовую программу. А заодно нехватка памяти похоронила вкладку Chrome, в которой я писал эту статью. И мне это не понравилось пусть даже автоматическое сохранение сработало. Я не люблю когда мои данные хоронят.

Включенный swap


Выставляем vm_swappines = 60 (по умолчанию)
Запускаем тест:
$ time ./swapdemoPreparing test ...Doing test ...Iteration 1 of 11Iteration 2 of 11Iteration 3 of 11Iteration 4 of 11Iteration 5 of 11Iteration 6 of 11Iteration 7 of 11Iteration 8 of 11Iteration 9 of 11Iteration 10 of 11Iteration 11 of 11real 1m55,291suser 0m2,692ssys 0m20,626s

Фрагмент top:
Tasks: 298 total,  2 running, 296 sleeping,  0 stopped,  0 zombie%Cpu(s): 0,6 us, 3,1 sy, 0,0 ni, 85,7 id, 10,1 wa, 0,5 hi, 0,0 si, 0,0 stMiB Mem : 15670,0 total,  156,0 free,  577,5 used, 14936,5 buff/cacheMiB Swap: 16384,0 total, 12292,5 free,  4091,5 used.  3079,1 avail MemPID USER   PR NI  VIRT  RES  SHR S %CPU %MEM   TIME+ COMMAND10393 viking  20  0  17,0g 14,2g 14,2g D 17,3 93,0  0:18.78 swapdemo136 root   20  0    0   0   0 S  9,6  0,0  4:35.68 kswapd0


Плохой-плохой линукс!!! Он использует swap почти на 4 гигабайт хотя у него 14 гигабайт кэша и 3 гигабайта доступно! У линукса неправильные настройки! Плохой outlingo, плохие старые админы, они ничего не понимают, они сказали включить swap и теперь у меня из-за них система свапится и плохо работает. Надо отключить swap как советуют намного более молодые и перспективные интернет-эксперты, ведь они точно знают что делать!

Ну Пусть будет так. Давайте максимально отключим свап по советам экспертов?

Тест почти без swap


Выставляем vm_swappines = 1

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

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

Сначала рассмотрим вывод top:

Tasks: 302 total,  1 running, 301 sleeping,  0 stopped,  0 zombie%Cpu(s): 0,2 us, 4,7 sy, 0,0 ni, 84,6 id, 10,0 wa, 0,4 hi, 0,0 si, 0,0 stMiB Mem : 15670,0 total,  162,8 free,  1077,0 used, 14430,2 buff/cacheMiB Swap: 20480,0 total, 18164,6 free,  2315,4 used.  690,5 avail MemPID USER   PR NI  VIRT  RES  SHR S %CPU %MEM   TIME+ COMMAND6127 viking  20  0  17,0g 13,5g 13,5g D 20,2 87,9  0:10.24 swapdemo136 root   20  0    0   0   0 S 17,2  0,0  2:15.50 kswapd0

Ура?! Свап используется всего лишь на 2.5 гигабайт, что почти 2 в два раза меньше чем в тесте со включенным swap (и swappiness=60). Свапа используется меньше. Свободной памяти тоже меньше. И наверное, мы можем смело отдать победу молодым экспертам. Но вот что странно наша программа так и не смогла завершить даже 1 (ОДНОЙ!) итерации за 2 (ДВЕ!) минуты:
$ { sleep 120 ; killall swapdemo ; } &[1] 6121$ time ./swapdemoPreparing test Doing test Iteration 1 of 11[1]+ Done          { sleep 120; killall swapdemo; }Terminatedreal1m58,791suser0m0,871ssys0m23,998s


Повторим программа не смогла завершить 1 итерацию за 2 минуты хотя в предыдущем тесте она сделала 11 итераций за 2 минуты то есть с почти отключенным свапом программа работает более чем в 10(!) раз медленнее.

Но есть один плюс ни одной вкладки Chrome не пострадало. И это хорошо.

Тест с полным отключением swap


Но может быть, просто задавить свап через swappiness недостаточно, и его надо полностью отключать? Естественно, что надо проверить и эту теорию. Мы сюда тесты пришли провести, или что?

Это идеальный случай:

  • унас нет свопа и все наши данные будут гарантированно в памяти
  • свап не будет использоваться даже случайно, потому что его нет


И теперь наш тест завершится со скоростью молнии, старики пойдут на заслуженное ими место и будут менять картриджи дорогу молодым.

К сожалению, результат запуска тестовой программы аналогичный не завершилось даже одной итерации.

Вывод top:
Tasks: 217 total,  1 running, 216 sleeping,  0 stopped,  0 zombie%Cpu(s): 0,0 us, 2,2 sy, 0,0 ni, 85,2 id, 12,6 wa, 0,0 hi, 0,0 si, 0,0 stMiB Mem : 15670,0 total,  175,2 free,  331,6 used, 15163,2 buff/cacheMiB Swap:   0,0 total,   0,0 free,   0,0 used.  711,2 avail MemPID USER   PR NI  VIRT  RES  SHR S %CPU %MEM   TIME+ COMMAND136 root   20  0    0   0   0 S 12,5  0,0  3:22.56 kswapd07430 viking  20  0  17,0g 14,5g 14,5g D  6,2 94,8  0:14.94 swapdemo

Почему это происходит


Объяснение очень простое сегмент кода который мы подключаем через mmap (libptr) лежит в кэше. Поэтому когда мы запрещаем (или почти запрещаем) swap тем или иным способом, не важно каким физическим ли отключением swap, или через vm.swappines=0|1 это всегда заканчивается одним и тем же сценарием вымыванием mmapнутого файла из кэша и последующей его загрузкой с диска. А библиотеки загружаются именно через mmap, и чтобы убедиться в этом, достаточно просто сделать ls -l /proc//map_files:

$ ls -l /proc/8253/map_files/ | head -n 10total 0lr-------- 1 viking viking 64 фев 7 12:58 556799983000-55679998e000 -> /usr/libexec/gnome-session-binarylr-------- 1 viking viking 64 фев 7 12:58 55679998e000-5567999af000 -> /usr/libexec/gnome-session-binarylr-------- 1 viking viking 64 фев 7 12:58 5567999af000-5567999bf000 -> /usr/libexec/gnome-session-binarylr-------- 1 viking viking 64 фев 7 12:58 5567999c0000-5567999c4000 -> /usr/libexec/gnome-session-binarylr-------- 1 viking viking 64 фев 7 12:58 5567999c4000-5567999c5000 -> /usr/libexec/gnome-session-binarylr-------- 1 viking viking 64 фев 7 12:58 7fb22a033000-7fb22a062000 -> /usr/share/glib-2.0/schemas/gschemas.compiledlr-------- 1 viking viking 64 фев 7 12:58 7fb22b064000-7fb238594000 -> /usr/lib/locale/locale-archivelr-------- 1 viking viking 64 фев 7 12:58 7fb238594000-7fb2385a7000 -> /usr/lib64/gvfs/libgvfscommon.solr-------- 1 viking viking 64 фев 7 12:58 7fb2385a7000-7fb2385c3000 -> /usr/lib64/gvfs/libgvfscommon.so

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

Заключение


Активное использование методики распространения программ всё свое везу с собой (flatpak, snap, docker image) приводит к тому, что количество кода, который подключается через mmap, существенно увеличивается.

Это может привести к тому, что использование экстремальных оптимизаций, связанных с настройкой/отключением swap, может привести к совершенно неожиданным эффектам, потому, что swap-файл это механизм оптимизации подсистемы виртуальной памяти в условиях memory pressure, а available memory это совсем не неиспользуемая память, а сумма размеров кэша и свободной памяти.

Отключая swap-файл, вы не убираете неправильный вариант, а не оставляете вариантов

Следует очень осторожно интерпретировать данные о потреблении памтяи процессом VSS и RSS. Они отображают текущее состояние а не оптимальное состояние.

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

P.S.: В обсуждениях регулярно задаются вопросы а вот если включить сжатие памяти через zram.... Мне стало интересно, и я провел соответствующие тесты: если включить zram и swap, как это сделано по умолчанию в Fedora, то время работы ускоряется примерно до 1 минуты.

Но причина этого то, что страницы с нулями очень хорошо сжимаются, поэтому на самом деле данные уезжают не в swap, а хранятся в сжатом виде в оперативной памяти. Если заполнить сегмент данных случайными плохосжимаемыми данными, картина станет не такой эффектной и время работы теста опять же увеличится до 2 минут, что сравнимо (и даже чуть хуже), чем у честного swap-файла.
Источник: habr.com
К списку статей
Опубликовано: 07.02.2021 16:04:25
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Настройка linux

Серверное администрирование

Разработка под linux

Linux

Swap

Оптимизация

Тестирование

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru