Назад | Перейти на главную страницу

Возможная проблема с таблицей страниц Linux / огромная средняя загрузка с JVM с большой кучей, что приводит к значительному системному времени в журналах GC

Наш сервис работает на 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. Размеры страниц - большая проблема.