Комментарии 24
Спасибо за статью!
+3
Отличная статья, спасибо большое!
Поправьте -XX+AlwaysActAsServerClassMachine на
Поправьте -XX+AlwaysActAsServerClassMachine на
-XX:+AlwaysActAsServerClassMachine
. И переменная окружения должна быть MALLOC_ARENA_MAX
вместо MALLOC_ARENAS_MAX
.+2
Спасибо за статью!
Еще можно послушать доклад Дмитрия — www.youtube.com/watch?v=m1XIdu2IKnM&list=PLojTLDAO4jjIRjDPIQjc4iG7CfR6m8pfc&index=4&t=0s
Еще можно послушать доклад Дмитрия — www.youtube.com/watch?v=m1XIdu2IKnM&list=PLojTLDAO4jjIRjDPIQjc4iG7CfR6m8pfc&index=4&t=0s
+1
Есть ли смысл в MALLOC_ARENA_MAX>1 для JVM?
0
Безусловно есть, чем больше арен, тем меньше конкуренции за них при вызове malloc. Но это с точки зрения теории, на практике всё зависит от приложения. Для наших типовых сервисов сокращение числа арен до 4 не повлияло никак на их производительность. Больше мы не эксперименировали, т.к. jemalloc зашёл лучше.
0
Вы вот вроде бы что-то ответили, но что — я так и не понял. Смысл есть, но зависит от приложения, но вы не пробовали.
0
Попробую развернуть)
Чем меньше арен, тем больше contention при использовании malloc. Теоретически это может привести к деградации производительности (тут всё зависит от приложения — насколько интенсивно в нём используется malloc).
На наших типовых сервисах мы не заметили никакого проседания при уменьшении числа арен с 640 (8 * 80) до 4. Ещё меньше ставить не пробовали, так как стали повсеместно внедрять jemalloc.
Чем меньше арен, тем больше contention при использовании malloc. Теоретически это может привести к деградации производительности (тут всё зависит от приложения — насколько интенсивно в нём используется malloc).
На наших типовых сервисах мы не заметили никакого проседания при уменьшении числа арен с 640 (8 * 80) до 4. Ещё меньше ставить не пробовали, так как стали повсеместно внедрять jemalloc.
+1
Очень интересная статья, но есть множество спорных моментов.
Вы отключаете overcommit памяти в Ось?
Если нет, то по сути большинство ограничений не уменьшают потребление памяти, если помнить о «ленивом» выделении памяти линуксом. Даже commited memory в NMT не отображает потребление памяти, а лишь максимальное, если jvm ее затребует. Поэтому, большинством этих настроек просто промениваете OOMKiller на OutOfMemoryError, StackOverFlow и т.д. Не знаю, есть ли такая цель, мне кажется общее ограничение дополнительно дает возможность для перераспределения памяти между областями если понадобится (overcommit).
1.-XX:ThreadStackSize ограничивает максимальный размер стэка потока, если вашим потоком столько не нужно, память не расходуется по 1мб на стэк, минимум от 228кб, то того размера который нужен. Уменьшение параметра потребление RSS не уменьшит
2. MALLOC_ARENA_MAX аналогично, в вашей же ссылке на сайт ibm какой-то бред, считать превышение vsz над rss мемори ликом и чинить это, хотя как раз и написано, что они оптимизируют virtual memory size, вы тоже оптимизируете vsz? Непонятно тогда откуда у вас график по уменьшению rss, наверняка это не rss, так как настройка влияет только на virtual memory, на RSS не влияет.
3. Code cache аналогично, если вы знаете что 240мб у вас не потребляется, то значит и памяти столько не используется. Ограничить можно, думаю что вытеснение кода при переполнении все таки менее болезненно, чем OOMKiller, но вы же хотите делать ExitOnFullCodeCache, значит вас это не волновало.
4. MaxMetaSpace аналогично, потребляется столько сколько нужно. Ставя настройку вы просто ограничиваете потенциальную утечку этим разделом, чтобы получить OutOfMemoryError, а не OOMKiller
Вы отключаете overcommit памяти в Ось?
Если нет, то по сути большинство ограничений не уменьшают потребление памяти, если помнить о «ленивом» выделении памяти линуксом. Даже commited memory в NMT не отображает потребление памяти, а лишь максимальное, если jvm ее затребует. Поэтому, большинством этих настроек просто промениваете OOMKiller на OutOfMemoryError, StackOverFlow и т.д. Не знаю, есть ли такая цель, мне кажется общее ограничение дополнительно дает возможность для перераспределения памяти между областями если понадобится (overcommit).
1.-XX:ThreadStackSize ограничивает максимальный размер стэка потока, если вашим потоком столько не нужно, память не расходуется по 1мб на стэк, минимум от 228кб, то того размера который нужен. Уменьшение параметра потребление RSS не уменьшит
2. MALLOC_ARENA_MAX аналогично, в вашей же ссылке на сайт ibm какой-то бред, считать превышение vsz над rss мемори ликом и чинить это, хотя как раз и написано, что они оптимизируют virtual memory size, вы тоже оптимизируете vsz? Непонятно тогда откуда у вас график по уменьшению rss, наверняка это не rss, так как настройка влияет только на virtual memory, на RSS не влияет.
3. Code cache аналогично, если вы знаете что 240мб у вас не потребляется, то значит и памяти столько не используется. Ограничить можно, думаю что вытеснение кода при переполнении все таки менее болезненно, чем OOMKiller, но вы же хотите делать ExitOnFullCodeCache, значит вас это не волновало.
4. MaxMetaSpace аналогично, потребляется столько сколько нужно. Ставя настройку вы просто ограничиваете потенциальную утечку этим разделом, чтобы получить OutOfMemoryError, а не OOMKiller
+1
По пункту 2. MALLOC_ARENA_MAX влияет именно на RSS, мы тоже с этим сталкивались: slonopotamus.livejournal.com/186275.html
0
В вашей статье из 4 ссылок 3 про virtual memory size и в одной про native memory leak. Да выходит если есть memory leak, то уменьшение кол-ва арен зажмет утечку в меньших рамках, это все объясняет, согласен, и если не удается починить утечку, то нужно уменьшать,
0
Спасибо за вопросы, попробую ответить по пунктам.
1. Честно говоря, не припомню, чтобы документация описывала ThreadStackSize как максимальный размер стека. Пруфа в виде ссылки на код у меня, к сожалению, под рукой нет, однако практика показывает, что объём закоммиченной под пул Threads памяти (по показаниям native memory tracking) уменьшается с уменьшением -XX:ThreadStackSize, независимое подтверждение есть у Алексея Шипилева в JVM Anatomy Quark #12: Native Memory Tracking.
2. На графике изображён именно RSS (метрика, которую сообщает cgroups). Большое число арен (которое масштабируется по числу цпу на хосте) ведёт к неоправданной фрагментации памяти, естественно это отражается на RSS.
3 и 4. Да, вы правы, от ограничения CodeCache и Metaspace JVM не начнёт потреблять меньше памяти, поэтому они в разделе «ограничения», а не «оптимизации». Для нас основной вопрос был в том, есть ли смысл разрешать приложению потреблять 240 Мб, когда ему больше 32 не нужно. Так что речь тут речь в основном о рациональном использовании ресурсов (лимиты в cgroups можем выставить поменьше и знать точно, сколько каких контейнеров поместится в хост-машину). Ну и получить Java-ООМ приятнее, чем системный — не надо лишний раз гадать что израсходовало память (для полного счастья не хватает ExitOnFullCodeCache).
1. Честно говоря, не припомню, чтобы документация описывала ThreadStackSize как максимальный размер стека. Пруфа в виде ссылки на код у меня, к сожалению, под рукой нет, однако практика показывает, что объём закоммиченной под пул Threads памяти (по показаниям native memory tracking) уменьшается с уменьшением -XX:ThreadStackSize, независимое подтверждение есть у Алексея Шипилева в JVM Anatomy Quark #12: Native Memory Tracking.
2. На графике изображён именно RSS (метрика, которую сообщает cgroups). Большое число арен (которое масштабируется по числу цпу на хосте) ведёт к неоправданной фрагментации памяти, естественно это отражается на RSS.
3 и 4. Да, вы правы, от ограничения CodeCache и Metaspace JVM не начнёт потреблять меньше памяти, поэтому они в разделе «ограничения», а не «оптимизации». Для нас основной вопрос был в том, есть ли смысл разрешать приложению потреблять 240 Мб, когда ему больше 32 не нужно. Так что речь тут речь в основном о рациональном использовании ресурсов (лимиты в cgroups можем выставить поменьше и знать точно, сколько каких контейнеров поместится в хост-машину). Ну и получить Java-ООМ приятнее, чем системный — не надо лишний раз гадать что израсходовало память (для полного счастья не хватает ExitOnFullCodeCache).
0
1. commited memory != RSS, при дефолтных настройках vm.overcommit_memory,
vm.overcommit_ratio на linux.
vm.overcommit_ratio на linux.
0
Я немного не о том. JVM (насколько я понимаю этот механизм) при создании треда вызывает pthread_attr_setstacksize со значением, высчитанным как раз из ThreadStackSize.
pthread_attr_setstacksize задаёт минимальный размер стека (он же становится максимальным для не-main треда): man7.org/linux/man-pages/man3/pthread_attr_setstacksize.3.html
pthread_attr_setstacksize задаёт минимальный размер стека (он же становится максимальным для не-main треда): man7.org/linux/man-pages/man3/pthread_attr_setstacksize.3.html
+1
Спасибо за статью. Спорные моменты конечно есть, но однозначно годится в качестве отправной точки в оптимизации размеров контейнеров с java-приложениями.
0
Наш опыт показывает, что Java в Docker — это не только удобно, но и в итоге довольно экономично. Надо только научиться их готовить.
С учётом того, что до этого у вас был kvm, а теперь Docker, в чём именно вышла экономия? Вы подходили с реальными цифрами (например, что с той же самой нагрузкой справляется парк машин на 20% серверов меньше и т.п.)? Ну или требуется меньше дискового пространства на 40%? Я про реальные цифры. Это было бы очень интересно узнать.
+1
Передал этот вопрос нашей команде эксплуатации:
Экономия по оперативной памяти — в kvm виртуалке свое ядро, система и стек приложений, на это 500-1000MB памяти надо закладывать, а это примерно двойной оверхед для мелких сервисов. Плюс контейнер может отдать память в систему сразу, а виртуалка только после рестарта (kvm baloon у нас приводил к проблемам).
По объёму и пропускной способности диска ещё выиграли — на каждую виртуалку раньше выделяли образ минимум по 10GB, c учётом того что у нас до 30 контейнеров на хост — это уже значительный оверхед на пустом месте, потому что большая часть железа работает в блейдах, где максимум 2 диска 2.5". И в нехватку дискового пространства гораздо чаще бы упирались — предсказать сколько места понадобится заранее не всегда возможно.
Производительность дисковой подсистемы с kvm отличается в разы от хостовой с некоторыми драйверами, до 200% оверхеда спокойно могло быть в некоторых случаях.
Ну и оверхед управления этим всем — рулить 1000 виртуалок вместо 1000 контейнеров с учётом прочих задач — это ещё наверное пару человек пришлось бы нанимать (тот же ресайз образа виртуалки это не самая быстрая задача, + ковыряние с srv-iov и настройками на каждой виртуалке). Релизы бы стали медленнее, если бы каждый плейбук еще системные конфиги на машины приносил, как было раньше
+5
Разве
-XX:+UseContainerSupport
есть теперь и Java 8? Вроде бы там вот такой аналог этой опции -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
.0
Появилась в 8u191 в октябре 2018
+1
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Как мы учились эксплуатировать Java в Docker