Наш сервис работает на AWS на узлах m5.12xlarge (48 ядер, 192 ГБ ОЗУ) в Ubuntu 16.04. Мы используем Java 8. Для нашего сервиса мы выделяем около 150 ГБ в качестве максимального размера кучи. У нас нет свопа на узле. Суть нашего сервиса в том, что он выделяет много крупных недолговечных объектов. Помимо этого, с помощью сторонней библиотеки, от которой мы зависим, мы создаем множество недолговечных процессов, которые взаимодействуют с нашим процессом по каналам и обрабатываются после обслуживания нескольких запросов.
Мы заметили, что когда-то после того, как процесс запущен, и RES (вверху) процесса достигает примерно 70G, прерывания ЦП значительно увеличиваются, а журналы GC JVM показывают, что системное время увеличивается до десятков секунд (иногда 70 секунд). Средние значения нагрузки, которые начинаются с <1, заканчиваются почти 10 на этих 48 основных узлах в этом состоянии.
Выходные данные sar показали, что когда узел находится в этом состоянии, минимальное количество ошибок страниц значительно увеличивается. В общем, с этим состоянием коррелирует большое количество прерываний процессора.
Перезапуск нашего сервиса дает лишь временную передышку. Средняя нагрузка медленно, но верно возрастает, и системное время ГХ снова резко увеличивается.
Мы запускаем нашу службу в кластере примерно из 10 узлов каждый с (почти) равномерно распределенной нагрузкой. Мы видим, что некоторые узлы переходят в это состояние чаще и быстрее, чем другие, которые работают нормально.
Мы безуспешно пробовали различные варианты GC, такие как большие страницы / THP и т. Д.
Вот снимок loadavg и meminfo
/proc/meminfo on a node with high load avg:
MemTotal: 193834132 kB
MemFree: 21391860 kB
MemAvailable: 52217676 kB
Buffers: 221760 kB
Cached: 9983452 kB
SwapCached: 0 kB
Active: 144240208 kB
Inactive: 4235732 kB
Active(anon): 138274336 kB
Inactive(anon): 24772 kB
Active(file): 5965872 kB
Inactive(file): 4210960 kB
Unevictable: 3652 kB
Mlocked: 3652 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 89140 kB
Writeback: 4 kB
AnonPages: 138292556 kB
Mapped: 185656 kB
Shmem: 25480 kB
Slab: 22590684 kB
SReclaimable: 21680388 kB
SUnreclaim: 910296 kB
KernelStack: 56832 kB
PageTables: 611304 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 96917064 kB
Committed_AS: 436086620 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
AnonHugePages: 85121024 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 212960 kB
DirectMap2M: 33210368 kB
DirectMap1G: 163577856 kB
/proc/meminfo on a node that is behaving ok
MemTotal: 193834132 kB
MemFree: 22509496 kB
MemAvailable: 45958676 kB
Buffers: 179576 kB
Cached: 6958204 kB
SwapCached: 0 kB
Active: 150349632 kB
Inactive: 2268852 kB
Active(anon): 145485744 kB
Inactive(anon): 8384 kB
Active(file): 4863888 kB
Inactive(file): 2260468 kB
Unevictable: 3652 kB
Mlocked: 3652 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 1519448 kB
Writeback: 0 kB
AnonPages: 145564840 kB
Mapped: 172080 kB
Shmem: 9056 kB
Slab: 17642908 kB
SReclaimable: 17356228 kB
SUnreclaim: 286680 kB
KernelStack: 52944 kB
PageTables: 302344 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 96917064 kB
Committed_AS: 148479160 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
AnonHugePages: 142260224 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 149472 kB
DirectMap2M: 20690944 kB
DirectMap1G: 176160768 kB
Наиболее значимая часть графика пламени:
https://i.stack.imgur.com/yXmOM.png
Случайно мы перезагрузили узел и заметили, что он работал очень стабильно около 2 недель без каких-либо изменений в других местах. С тех пор мы прибегали к перезагрузке узлов, которые попали в это состояние, чтобы получить передышку. Позже мы обнаружили в другом месте, что эти симптомы могут быть связаны с заклиниванием таблицы страниц, которое можно смягчить только перезагрузкой. Неясно, правильно ли это и является ли это причиной нашей ситуации.
Есть ли способ решить эту проблему навсегда?
Прозрачные огромные страницы становятся фрагментированными или перемешиваются. В Linux следует рассмотреть вопрос об отказе от прозрачности и явной настройке размеров страниц при таком размере памяти.
Отличия больше 10 ГБ, в минус хорошо:
Committed_AS: 274.3
AnonHugePages: -54.5
DirectMap2M: 11.9
DirectMap1G: -12.0
Переход от DirectMap с 1G к 2M показывает, как внутри x86 TLB и Linux было меньше непрерывного пространства для работы. Большая разница там теряется 50 ГБ от AnonHugePages. Каким-то образом это увеличило Committed_AS до 225% от вашего MemTotal, что является плохим симптомом; эта система выйдет из строя как сумасшедшая.
Учитывая ошибки страниц в стеке графа пламени, вы получаете большие накладные расходы из-за перетасовки страниц системой виртуальной памяти Linux.
Повышение производительности включает явную настройку огромных страниц. 150 ГБ кучи намного превышают точку перехода 30 ГБ, когда сжатые указатели больше не доступны. (Много было написано о том, чтобы оставаться ниже этого порога в 30 ГБ.) Трехзначный ГБ также является размером, в котором я считаю, что огромные страницы Linux должны быть серьезно оценены.
В OpenJDK или Oracle JDK: сначала правильно распределите огромные страницы, затем используйте опцию -XX:+UseLargePages
. Поддержка Java для больших страниц памяти и Вики Debian на HugePages
Если вы также хотите поэкспериментировать со сборщиками мусора, посмотрите Вики-страница OpenJDK ZGC. Ограниченное время паузы, обработка больших куч и осведомленность о NUMA - явные цели. Короче, также попробуйте экспериментальные варианты: -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:+UseLargePages
. На вики-странице ZGC также обсуждается проблема с огромными пулами страниц Linux и hugetlbfs, всегда полезно иметь примеры таких вещей.
Что касается NUMA, подумайте на минутку о процессоре, на котором он будет работать. Вероятно, два 24-ядерных разъема или около того. AWS не является конкретным, но говорят, что это был Платина 8175. Поскольку вы будете выполняться в разных сокетах, часть памяти не будет локальной для сокета. Это верно, даже если гипервизор не предоставляет эту топологию гостевой виртуальной машине.
Однако два сокета на современном Xeon могут иметь управляемые эффекты NUMA. Размеры страниц - большая проблема.