Java protobuf создает слишком много объектов - PullRequest
1 голос
/ 07 марта 2019

У меня есть прокси-сервер на сервере Jetty между бэкендом и конвертированием protobufs frontend.proto-> backend.proto и backend.proto-> frontend.proto.

Запросы занимают менее 20 мс (99-й) и 40 мс (99,9-й)) пока нагрузка не достигает пика.
Однако, когда нагрузка достигает пика, 99-й увеличивается на +10, а 99-й увеличивается на + 60.

Я исследовал это, и отложенные запросы вызваны паузами эвакуации ГХВ этом я уверен, что эти паузы занимают 50-70 мс и запускаются каждые 15 секунд при нагрузке в долине, но при пиковой нагрузке они увеличиваются до одного раза в 3-5 секунд, продолжительность такая же.
Как только ГХчастота опускается ниже 8-9 секунд, 99,9-й процентиль запускается, и я вижу журналы отладки медленных запросов одновременно с журналом GC.

Я профилировал с JProfiler, Yourkit и VisualVM и увидел, что:

  • Заполняется пространство Eden и запускается GC-пауза
  • Очень мало объектовперешел в Survivor (несколько МБ из 12G)
  • Таким образом, большинство объектов уже истекло в Eden
  • Это имеет смысл, поскольку запросы занимают 30-40 мс, а большая часть времени жизни объектов связана свремя жизни запроса
  • Большинство объектов создаются во время десериализации протобуфа

Я пытался поиграть с размерами GCPauseMillis и Eden, но, кажется, ничто не имеет значения, оно никогда не требует меньшечем 50 мс и больше Eden означает меньшую частоту, но гораздо более длинные паузы

Я вижу здесь 2 варианта:

  1. Как-то повторно использовать создание объекта в java-protobuf: кажется невозможным, прочитайте многосообщения и письма, и они не настроены таким образом, они просто говорят, что «распределение объектов Java очень эффективно, и оно должно быть в состоянии обрабатывать многие создаваемые объекты»и хотя это так, связанные с этим затраты на сборку мусора убивают мою 99,9-ю
  2. , чтобы заставить сборщик мусора запускаться чаще, скажем раз в секунду, чтобы сократить время сбора, чтобы остановить больше запросов, но на более короткие промежутки времени.: Я играл с размерами GCMaxMillis и Eden, но я не могу получить его ниже, чем

Я загрузил журнал gc в gc_log

Версия Java:

java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

Сведения о GC: * ​​1040 *

-XX:CICompilerCount=12 -XX:ConcGCThreads=5 -XX:ErrorFile=/home/y/var/crash/hs_err_pid%p.log -XX:+FlightRecorder -XX:G1HeapRegionSize=4194304 -XX:GCLogFileSize=4194304 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/y/logs/yjava_jetty -XX:InitialHeapSize=12884901888 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=12884901888 -XX:MaxNewSize=7730102272 -XX:MinHeapDeltaBytes=4194304 -XX:NumberOfGCLogFiles=10 -XX:+ParallelRefProcEnabled -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UnlockCommercialFeatures -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:+UseGCLogFileRotation
...