Эксперименты и увлекательные манипуляции с дисковым кэшем Linux

—

от автора

Надеюсь, теперь вы убедились, что Linux не “съел” всю вашу оперативную память. Вот несколько интересных вещей, которые вы можете сделать, чтобы узнать, как работает дисковый кэш.

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

Влияние дискового кэша на аллокацию памяти приложениями

Поскольку я уже заверил, что дисковый кэш не мешает приложениям получать нужную им память, давайте с этого и начнем. Вот приложение на языке Си (munch.c), которое поглотит столько памяти, сколько сможет, или до заданного предела:

#include <stdlib.h> #include <stdio.h> #include <string.h>  int main(int argc, char** argv) {     int max = -1;     int mb = 0;     char* buffer;      if(argc > 1)         max = atoi(argv[1]);      while((buffer=malloc(1024*1024)) != NULL && mb != max) {         memset(buffer, 0, 1024*1024);         mb++;         printf("Allocated %d MB\n", mb);     }      return 0; }

Закончившаяся память — это не очень весело, но механизм OOM (Out-Of-Memory) killer должен завершить только этот процесс и, надеюсь, остальные останутся нетронутыми. Мы определенно захотим отключить своп в данном случае, иначе приложение поглотит и его.

$ sudo swapoff -a  $ free -m

(обратите внимание, что ваш вывод free может быть другим, и иметь столбец ‘available’ (доступная) вместо строки ‘-/+’)

             total       used       free     shared    buffers     cached Mem:          1504       1490         14          0         24        809 -/+ buffers/cache:        656        848 Swap:            0          0          0  $ gcc munch.c -o munch  $ ./munch Allocated 1 MB Allocated 2 MB (...) Allocated 877 MB Allocated 878 MB Allocated 879 MB Killed  $ free -m               total       used       free     shared    buffers     cached Mem:          1504        650        854          0          1         67 -/+ buffers/cache:        581        923 Swap:            0          0          0

Несмотря на то, что было указано 14 МБ «free» (свободная), это не помешало приложению захватить 879 МБ. После этого кэш практически пуст[2], но постепенно он снова заполнится по мере чтения и записи файлов. Попробуйте.

Влияние дискового кэша на свопинг

Я также сказал, что кеш диска не заставит приложения использовать своп (подкачку). Давайте попробуем и это, с тем же приложением munch, что и в предыдущем эксперименте. На этот раз мы запустим его с включенным свопом и ограничимся несколькими сотнями мегабайт:

$ free -m              total       used       free     shared    buffers     cached Mem:          1504       1490         14          0         10        874 -/+ buffers/cache:        605        899 Swap:         2047          6       2041  $ ./munch 400 Allocated 1 MB Allocated 2 MB (...) Allocated 399 MB Allocated 400 MB  $ free -m              total       used       free     shared    buffers     cached Mem:          1504       1090        414          0          5        485 -/+ buffers/cache:        598        906 Swap:         2047          6       2041

munch “съел” 400MB оперативной памяти, которая была взята из дискового кэша, не обращаясь к свопу. Аналогично, мы можем снова заполнить дисковый кэш, и он также не станет использовать своп. Если в одном терминале запустить watch free -m и find . -type f -exec cat {} + > /dev/null в другом, вы увидите, что «cached» (кэшированная) память будет расти, а «free» падать. Через некоторое время это замедляется, но своп так и остается нетронутым[1].

Очистка дискового кэша

При проведении экспериментов очень удобно иметь возможность сбросить дисковый кэш. Для этого мы можем использовать специальный файл /proc/sys/vm/drop_caches. Записав в него значение 3, мы можем очистить большую часть дискового кэша:

$ free -m              total       used       free     shared    buffers     cached Mem:          1504       1471         33          0         36        801 -/+ buffers/cache:        633        871 Swap:         2047          6       2041  $ echo 3 | sudo tee /proc/sys/vm/drop_caches  3  $ free -m              total       used       free     shared    buffers     cached Mem:          1504        763        741          0          0        134 -/+ buffers/cache:        629        875 Swap:         2047          6       2041

Обратите внимание, что «buffers» (буфера. буферная память) и «cached» уменьшились, free mem (свободная память) увеличилась, а free+buffers/cache остались прежними.

Влияние дискового кэша на время загрузки

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

$ cat hello.py print "Hello World! Love, Python"  $ cat Hello.java class Hello {     public static void main(String[] args) throws Exception {         System.out.println("Hello World! Regards, Java");     } }  $ javac Hello.java  $ python hello.py Hello World! Love, Python  $ java Hello Hello World! Regards, Java

Наши приложения “hello world” работают. Теперь давайте сбросим дисковый кэш и посмотрим, сколько времени потребуется для их запуска.

$ echo 3 | sudo tee /proc/sys/vm/drop_caches 3  $ time python hello.py Hello World! Love, Python  real    0m1.026s user    0m0.020s sys     0m0.020s  $ time java Hello Hello World! Regards, Java  real    0m2.174s user    0m0.100s sys     0m0.056s  $

Ого. 1 секунда для Python и 2 секунды для Java? Это много, чтобы просто сказать «привет» (hello). Однако теперь все файлы, необходимые для их запуска, будут находиться в дисковом кэше, поэтому их можно будет получить прямо из памяти. Давайте попробуем еще раз:

$ time python hello.py Hello World! Love, Python  real    0m0.022s user    0m0.016s sys     0m0.008s  $ time java Hello Hello World! Regards, Java  real    0m0.139s user    0m0.060s sys     0m0.028s  $

Ура! Теперь Python запускается всего за 22 миллисекунды, в то время как java использует 139 мс. Это в 45 и 15 раз быстрее! Все ваши приложения получают этот буст автоматически!

Влияние дискового кэша на чтение файлов

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

$ echo 3 | sudo tee /proc/sys/vm/drop_caches 3  $ free -m              total       used       free     shared    buffers     cached Mem:          1504        546        958          0          0         85 -/+ buffers/cache:        461       1043 Swap:         2047          6       2041  $ dd if=/dev/zero of=bigfile bs=1M count=200 200+0 records in 200+0 records out 209715200 bytes (210 MB) copied, 6.66191 s, 31.5 MB/s  $ ls -lh bigfile -rw-r--r-- 1 vidar vidar 200M 2009-04-25 12:30 bigfile  $ free -m              total       used       free     shared    buffers     cached Mem:          1504        753        750          0          0        285 -/+ buffers/cache:        468       1036 Swap:         2047          6       2041

Поскольку файл был только что записан, он отправится в дисковый кэш. Файл размером 200 МБ привел к увеличению «cached» на 200 МБ. Давайте его прочтем, очистим кэш и прочитаем снова, чтобы посмотреть, насколько это быстро:

$ time cat bigfile > /dev/null  real    0m0.139s user    0m0.008s sys     0m0.128s  $ echo 3 | sudo tee /proc/sys/vm/drop_caches 3  $ time cat bigfile > /dev/null  real    0m8.688s user    0m0.020s sys     0m0.336s  $

Это более чем в пятьдесят раз быстрее!

Выводы

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


В данном материале есть немного полезной информации:

  1. Хотя вновь аллоцированная память всегда (впрочем, см. пункт #2) будет браться из дискового кэша вместо свопа, Linux может быть сконфигурирован для предварительной выгрузки других неиспользуемых приложений в фоновом режиме, чтобы освободить память для кэша. Это настраивается с помощью параметра swappiness, доступного через /proc/sys/vm/swappiness.

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

  2. Некоторые части кэша не могут быть сброшены, даже для размещения новых приложений. К ним относятся mmap-страницы, которые были заблокированы системным вызовом mlock какого-либо приложения, «грязные» страницы (dirty pages), пока не записанные в память, и данные, хранящиеся в tmpfs (включая /dev/shm, используемую для общей памяти). Заблокированные (mlocked) mmap-страницы застревают в кэше страниц. «Грязные» страницы в большинстве случаев будут быстро переписаны. Данные в tmpfs по-возможности будут выгружены.


На днях пройдет открытый урок «LVM для начинающих», на котором разберем основные моменты использования LVM для организации дисковой системы в Linux. На занятии узнаем, что такое LVM и когда он нужен, что в него входит (PV, VG, LV). А также научимся, что можно сделать с его использованием. Регистрация открыта по ссылке.


ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/706702/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *