40-миллисекундная пауза Go GC из-за swap

A 40ms Go garbage collector pause caused by swap

40-миллисекундная пауза Go GC из-за swap

Автор запустил swap в продакшене, чтобы сгладить пики памяти, и обнаружил неожиданный эффект: метаданные сборщика мусора Go могут оказаться в swap, что приводит к stop-the-world паузам до 40 мс. В тестах на Hetzner с ядром 6.8 и MGLRU медианная пауза составляла 51 мкс, но худший случай достиг 40 мс, из которых 39 мс ушли на 228 page faults в служебных структурах GC. Автор также заметил, что сборка сообщения размером 511 КиБ замедлилась с 3–5 мс до 105 мс на NVMe и до 903 мс на сетевом томе. Обновление: Green Tea GC в Go 1.26 не меняет ситуацию.

«40 мс — это в 800 раз больше медианной паузы. За время теста это происходит два-три раза на каждый всплеск памяти. Это много.»
  1. nasretdinov

    К сожалению, это в какой-то степени ожидаемо — независимо от реализации, сам факт того, что GC должен так или иначе обойти всё дерево, чтобы отследить всё ещё используемые участки, делает swap крайне непрактичным — даже если бы у вас не было 40-миллисекундных stop-the-world пауз, LRU-кэш, используемый swap, выбрасывался бы при каждой сборке мусора.

    Я полагаю, что именно по этой же причине Apple отказалась от GC в своих фреймворках в пользу автоматического подсчёта ссылок.

  2. jacobgold

    «Мне больно, когда я делаю так»

    «Перестань так делать»

    Если вам важна задержка, отключите swap. Системно или для конкретной cgroup.

  3. pizlonator

    Есть ли причина, по которой Go не использует on-the-fly GC, где STW вообще отсутствует?

  4. xavdid

    Discord узнал об этом ещё в 2020 году и опубликовал отличный пост в блоге: https://discord.com/blog/why-discord-is-switching-from-go-to...

  5. soltanov

    SLO по задержке GC должен учитывать давление на память операционной системы. Иначе проблема с page-fault будет выглядеть как проблема сборщика и приведёт к неверному исправлению.

  6. Gabrys1

    Я начал задумываться, может ли существовать swap-aware GC, например, сначала подгрузить нужную страницу из swap (хотя очевидного API для этого нет...), и только потом останавливать мир?

  7. imclaren

    Вот именно. Баги с раздуванием памяти в Go исправлять относительно легко, но иногда удаление раздувания из-за swap превращается в целое приключение. И я считаю, что стоит избавиться от любого раздувания из-за swap!

  8. faangguyindia

    Я использую Go там, где использовал бы Node, Ruby или Python.

    Я использую Rust там, где мне нужна низкая задержка.

Ещё за этот день

2026-10-05