Найти в Дзене
Записки сисадмина

Linux снова сожрал всю память. Использование RAM простыми словами.

Оглавление

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

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

Давайте попробуем простыми словами разобраться в том, что такое оперативная память.

Ключевое слово - память. Но ведь жесткий диск - это тоже память. Получается, диск может спокойно выполнять роль RAM. Не совсем так. Ранее я уже писал про SWAP и с чем его едят.

Настало время разобраться с RAM. Если очень грубо - как и HDD/SSD, оперативная память - это некое пространство, в которое можно писать данные и читать их оттуда. Разница лишь в скорости этих операций и в том, что оперативная память очистится сразу после перезагрузки. Все данные, хранящиеся в ней - временные.

Почему тогда система не пишет все сразу на диск, если, в теории, технически это возможно?

Все просто: скорость и надежность.

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

В linux существует 3 вида памяти: виртуальная (virtual), физическая (physical) и разделяемая (shared).

Если в двух словах:

  • Виртуальная память - память, которая выделяется системой процессу. Может быть в разы больше, чем доступно в самой системе. Нужна для защищенной работы процессов и для изоляции ядра. Виртуальной памяти выделяется всегда больше, чем нужно, на случай, если процесс внезапно начнет потреблять больше ресурсов. Количество можно настроить с помощью директивы overcommit_memory.
  • Физическая память - выделяется в тот момент, когда процесс начинает что-то писать. Процесс запрашивает у ядра память, ядро в свою очередь сопоставляет карту памяти и выделяет адреса для процесса. По сути, физическая память - это реальное потребление процесса.
  • Разделяемая память - нужна для взаимодействия процессов. Поскольку все процессы изолированы друг от друга, обмениваться данными они могут только через области shared памяти. Также, в shared память подгружаются общие библиотеки (например, библиотеки python).

С теорией мы разобрались. Давайте теперь посмотрим, как наша система использует оперативную память:

Зайдем на один из наших серверов и посмотрим потребление памяти.

вывод top
вывод top
вывод htop
вывод htop

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

В случае с сервером на Windows, у нас были бы серьезные проблемы. Но в нашем консольном мире все устроено немного иначе.

Есть прекрасный сайт linuxatemyram, на котором описано, как именно linux использует память, и почему на правильно спроектированном сервере потребление всегда будет приближаться к 100%.

Давайте посмотрим на вывод команды free -h

-3

Взгляд неопытного человека сразу упадет на графу "free", где видно, что свободно всего 2ГБ памяти из 125. Но при этом, сервер работает стабильно и без проблем. В чем же магия?

Видели наверно кучу мемов про Google Chrome и оперативную память?

-4

Вот с ядром linux происходит примерно то же самое.

"У тебя все еще есть память? Значит, она мне нужна!"

-5

Вот только в отличии от Chrome, у ядра linux есть инстинкт самосохранения. Система догадывается, что переполнение оперативной памяти влечет за собой мгновенный крах самой системы. С другой стороны, ядро linux будет стараться использовать выделенные ресурсы оптимально, чтобы максимально быстро обрабатывать все данные.

Давайте разбираться в выводе команды free:

На сервер мы посмотрели, теперь взглянем на обычный ноутбук.

-6

Вроде ситуация выглядит намного лучше, чем на сервере. Но нет.

Что же тогда означают директивы:

total - Тут все просто. Это вся установленная физическая память в системе.

used - Используемая память. Точнее - сумма всей используемой изолированной памяти всех процессов в конкретный момент времени.

shared - Разделяемая память. Та область, которая выделена процессам для общения друг с другом.

buff/cache - Весь кеш, который хранит система (подробнее - чуть позже).

available - Та память, которая может быть выделена. Примерно равна сумме free и buff/cache.

free - Свободная память. Та память, которую система не использует ВООБЩЕ.

Посмотрим на uptime системы:

-7

Выходит, за почти 6 дней, система так и не придумала, куда ей использовать четверть доступной памяти. А это значит только то, что в проектировании я допустил ошибку и установил слишком много оперативной памяти.

А что же такое cache?

Давайте смоделируем:

Мы открыли на своем ПК нереально большую Excel таблицу размером в 1ГБ, полистали ее, нашли что нужно и закрыли. Как в этой ситуации поведет себя наша система?

Напомню: ядро довольно умное. А еще оно поступает очень логично:

  • Тебе нужно открыть файл, значит я прочитаю все его содержимое и помещу это в buff/cache.
  • Память, которую будет использовать сам процесс, будет в разделе used.
  • Ты закрыл файл, но, возможно, он тебе еще понадобится.
  • Чтение с диска занимает очень много времени, а у нас еще много свободной памяти.
  • Я оставлю эти данные в кеше, пока нам не понадобится освободить память.

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

Кстати, если вы изменили файл, но еще не сохранили его, все изменения будут также в пространстве buff/cache.

В Linux есть команда sync, которая позволяет насильно записать все данные из памяти на диск, но это никак не освободит кеш, потому что sync ничего не зачищает, а только записывает.

Как мы можем сбросить cache и освободить память:

echo 1 > /proc/sys/vm/drop_caches

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

echo 2 > /proc/sys/vm/drop_caches

Очистит только кеш объектов inode и dentry (данные о файловой системе, пути и метаданные файлов)

echo 3 > /proc/sys/vm/drop_caches

Очистка всего кеша, и объектов, и страниц.

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

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

Резюмируем:

  1. Linux всегда будет стараться использовать нашу оперативную память по максимуму.
  2. Пока есть свободная память, ядро будет хранить данные файлов в buff/cache.
  3. Паниковать стоит только в тех случаях, когда available память стремится к нулю.
  4. Если вывод команды "dmesg | grep oom-killer" не пустой, значит недавно ядру приходилось аварийно завершать какой-то процесс из-за утечки памяти, и настало время разобраться, что пошло не по плану.