Как стать автором
Обновить
822.32
OTUS
Цифровые навыки от ведущих экспертов

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

Время на прочтение 5 мин
Количество просмотров 6.2K
Автор оригинала: linuxatemyram.com

Надеюсь, теперь вы убедились, что 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). А также научимся, что можно сделать с его использованием. Регистрация открыта по ссылке.

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

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS