Фрагментация памяти Linux

20

Есть ли способ обнаружить фрагментацию памяти в Linux? Это связано с тем, что на некоторых долго работающих серверах я заметил снижение производительности и только после перезапуска процесса я вижу лучшую производительность. Я заметил это больше при использовании поддержки огромных страниц linux - огромные страницы в linux более подвержены фрагментации?

В частности, я посмотрел / proc / buddyinfo. Я хочу знать, есть ли более эффективные способы (не только команды CLI как таковые, любая программа или теоретическое обоснование), чтобы посмотреть на это.

Рагу
источник
Я не смотрю только на быстрые решения командной строки, подойдет любая простая программа / теория. Следовательно, я не спрашивал при сбое сервера.
Raghu
1
Я не понимаю здесь один момент. Насколько я понимаю, фрагментация памяти должна приводить к нехватке памяти и, как следствие, к ошибкам выделения памяти. Однако вы спрашиваете о снижении производительности. Это потому, что у вас много памяти, подкачанной на диск? И если да, то что дают vmstatв поле so?
@skwllsp - отредактировал мой ответ, чтобы быть более конкретным.
Тим Пост
@Raghu - я бы не ожидал, что большинство системных администраторов изменят код ядра, чтобы управление памятью работало иначе, однако опытные администраторы Linux должны знать хотя бы общее представление о том, как Linux управляет памятью. Этот вопрос действительно на линии. Я проголосовал за его миграцию просто потому, что не могу предложить (в своем ответе) код, который отвечает на ваш вопрос. Чтение из / proc или использование vmstatявляется обычным пользовательским опытом. Если бы вы писали программу для того же, она была бы другой. Если вы собираетесь использовать bash для сбора этой информации, отредактируйте ваш вопрос, он не будет закрыт :)
Tim Post
@Tim - Поскольку я предположил, что это не только команды bash / cli, которые я хотел знать, мне нужна была информация, чтобы помочь мне в моей процедуре сравнительного анализа (для анализа результатов, а не для их запуска).
Рагу

Ответы:

12

Я отвечаю на тег . Мой ответ специфичен только для Linux .

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

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

Причина, по которой вы видите снижение производительности на долго работающих серверах, наиболее вероятна из-за того, что выделенные блоки, которые не были явно заблокированы (например, mlock()/ mlockall()или posix_madvise()) и не модифицированы в течение некоторого времени, были выгружены , что означает, что ваша служба переходит на диск, когда она должна прочитать их. Изменение этого поведения делает ваш процесс плохим соседом , поэтому многие люди размещают свои RDBMS на совершенно другом сервере, чем web / php / python / ruby ​​/ что угодно. Разумно, единственный способ исправить это - снизить конкуренцию за смежные блоки.

Фрагментация действительно заметна (в большинстве случаев) только тогда, когда страница A находится в памяти, а страница B перемещена в область подкачки. Естественно, перезапуск вашего сервиса, похоже, «излечит» это, но только потому, что ядро ​​еще не имело возможности вывести из процесса (в настоящее время) вновь выделенные блоки в пределах его коэффициента перегрузок.

Фактически, перезапуск (скажем, «apache») при высокой нагрузке, скорее всего, отправит блоки, принадлежащие другим сервисам, прямо на диск. Так что да, «apache» улучшится на короткое время, но «mysql» может пострадать… по крайней мере, пока ядро ​​не заставит их страдать одинаково, когда просто не хватает достаточной физической памяти.

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

Попробуйте vmstatполучить обзор того, что на самом деле хранится где.

Тим Пост
источник
Спасибо за ответ. Я использовал огромные страницы (размер = 2048 КБ каждая) для mysql - буферного пула innodb - чтобы посмотреть, насколько хорошо он работает (с использованием sysbench). Первоначально, когда время работы процесса (и даже время работы системы) было низким, это давало очень хорошие результаты. Тем не менее, его производительность начала ухудшаться в течение нескольких прогонов. Относительно страницы, которую вы упомянули, я, конечно, заметил высокую активность виртуальных машин, но я предположил, что это могло быть связано с сбросом журнала тестов и innodb (активность vm выше с большими страницами, чем без). Я также установил vm.swappiness на 1. Я не мог заметить каких-либо радикальных изменений.
Рагу
Согласно прекрасному руководству , «Огромные страницы не могут быть выгружены под давлением памяти». Я думаю, что это хороший ответ в стандартной памяти w / r / t, но не для огромных страниц.
Дэн Притц
5

ядро

Для получения текущего индекса фрагментации используйте:

sudo cat /sys/kernel/debug/extfrag/extfrag_index

Для дефрагментации памяти ядра попробуйте выполнить:

sysctl vm.compact_memory=1  

Также вы пытаетесь отключить прозрачные огромные страницы (иначе THP) и / или отключить обмен (или уменьшить swappiness).

Местоположение пользователя

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

Вы можете переключиться на пользовательский malloc, перекомпилировав с ним свою программу или просто запустив программу с LD_PRELOAD: LD_PRELOAD=${JEMALLOC_PATH}/lib/libjemalloc.so.1 app (остерегайтесь взаимодействий между THP и распределителями памяти )

Хотя, немного не связанный с фрагментацией памяти (но связанный с уплотнением / миграцией памяти), вы, вероятно, захотите запустить несколько экземпляров вашей службы, по одному для каждого узла NUMA, и связать их, используя numactl.

SaveTheRbtz
источник
1
Почему вы думаете, что отключение свопа может помочь? Мне кажется более вероятным, что отключение свопа повредит еще больше.
kasperd
1
Поскольку в исходном сообщении недостаточно информации, возможно, процесс просто просочился и начался обмен. Также я не вижу никаких законных причин для использования свопа практически на любой производственной системе (мб только для общих рабочих станций для студентов).
SaveTheRbtz
2
Наличие достаточного пространства подкачки улучшит производительность. Проблемы с производительностью, которые вы получите, если у вас недостаточно места подкачки, являются достаточной причиной для включения подкачки.
Касперд
1
@SaveTheRbtz Хорошая причина для использования свопа в производственной системе заключается в том, что она дает системе больше возможностей, которые она будет использовать, только если считает, что они полезны. Кроме того, он позволяет извлекать из драгоценной физической памяти измененные страницы, к которым не обращались в течение нескольких часов (и, возможно, никогда не получат доступ). Наконец, это позволяет системе разумно обрабатывать случаи, когда зарезервировано гораздо больше памяти, чем используется.
Дэвид Шварц
2
«Только если он считает, что они полезны», - это добавляет дополнительную эвристику и делает систему менее предсказуемой. Кроме того, алгоритмы замены страниц (используемые в swap и anonymous mmap) по-разному реализованы в разных ядрах (например, Linux против FreeBSD) или даже в разных версиях одной и той же ОС (2.6.32 против 3.2 против 3.10) .. "Это позволяет изменять страницы [. ..] будет извлечен из [...] физической памяти "- это позволит скрыть утечки памяти. «обрабатывать случаи, когда зарезервировано гораздо больше памяти, чем используется» - медленная система намного хуже, чем неработающая система, поэтому «вменяемая» сомнительна.
SaveTheRbtz
4

Использование огромных страниц не должно вызывать дополнительной фрагментации памяти в Linux; Поддержка огромных страниц в Linux предназначена только для разделяемой памяти (через shmget или mmap), и любые используемые огромные страницы должны быть специально запрошены и предварительно выделены системным администратором. Оказавшись в памяти, они там закреплены и не выгружены. Проблема обмена большими страницами перед лицом фрагментации памяти заключается именно в том, почему они остаются закрепленными в памяти (при выделении огромной страницы размером 2 МБ ядро ​​должно найти 512 смежных свободных страниц объемом 4 КБ, которых может даже не быть).

Linux документация на огромных страницах: http://lwn.net/Articles/375098/

Существует одно обстоятельство, при котором фрагментация памяти может привести к медленному распределению огромных страниц (но не в том случае, когда огромные страницы вызывают фрагментацию памяти), и это в том случае, если ваша система настроена для увеличения пула огромных страниц по запросу приложения. Если / proc / sys / vm / nr_overcommit_hugepages больше, чем / proc / sys / vm / nr_hugepages, это может произойти.

jstultz
источник
Действительно - и это, как правило, должно помочь производительности, потому что это предотвратит промахи TLB (см. Связанную статью для объяснения).
Дэн Притц
0

Есть /proc/buddyinfoчто очень полезно. Это более полезно с хорошим форматом вывода, как этот скрипт Python может сделать:

https://gist.github.com/labeneator/9574294

Для больших страниц вам нужны бесплатные фрагменты размером 2097152 (2MiB) или больше. Для прозрачных огромных страниц он автоматически сжимается, когда ядро ​​запрашивает некоторые из них, но если вы хотите увидеть, сколько вы можете получить, выполните команду root:

echo 1 | sudo tee /proc/sys/vm/compact_memory

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

У меня есть решение, которое работает для меня. Я использую это на нескольких серверах и моем ноутбуке. Отлично работает на виртуальных машинах.

Добавьте kernelcore=4Gопцию в вашу командную строку ядра Linux. На моем сервере я использую 8G. Будьте осторожны с числом, потому что оно не позволит вашему ядру распределять что-либо за пределами этой памяти. Серверы, которым требуется много буферов сокетов или потоковая запись на сотни дисков, не хотели бы ограничиваться таким образом. Любое распределение памяти, которое должно быть "закреплено" для плиты или прямого доступа к памяти, находится в этой категории.

Вся остальная ваша память затем становится «подвижной», что означает, что она может быть сжата в красивые куски для огромного размещения страниц. Теперь прозрачные огромные страницы могут действительно работать и работать так, как они должны. Всякий раз, когда ядру нужно больше 2M страниц, оно может просто переназначить 4K страницы куда-нибудь еще.

И я не совсем уверен, как это взаимодействует с прямым вводом-выводом без копирования. Память в «подвижной зоне» не должна быть закреплена, но прямой запрос ввода-вывода сделает именно это для DMA. Это может скопировать это. В любом случае это может закрепить его в подвижной зоне. В любом случае это, вероятно, не совсем то, что вы хотели.

Зан Рысь
источник