스왑 때문에 발생한 40ms Go GC 중단
A 40ms Go garbage collector pause caused by swap

프로덕션에서 스왑을 켠 후 Go의 가비지 컬렉터가 stop-the-world 중단 중에 스왑된 메타데이터를 읽으면서 40ms의 지연이 발생했다. 228번의 페이지 폴트가 중단 시간의 대부분을 차지했고, 30분 동안 312번의 중단이 있었다. 또한 511KiB 메시지 생성 시간이 NVMe에서 105ms, 네트워크 볼륨에서 903ms로 늘어났다. Go 1.26의 Green Tea GC도 이 영향을 받지 않았다.
40ms는 중간값 중단 시간의 800배다. 테스트 중 메모리 스파이크마다 두세 번씩 발생한다. 이건 정말 크다.
HN 토론
113- nasretdinov
안타깝게도 이건 어느 정도 예상된 일이에요 - 구현 방식과 무관하게, GC가 여전히 참조되고 있는 섹션을 추적하려면 전체 트리를 어떻게든 순회해야 한다는 사실 자체만으로도 swap은 매우 비현실적이 됩니다. 40ms stop-the-world 일시 중지가 없었더라도 swap이 사용하는 LRU 캐시는 매 GC마다 버려지게 될 테니까요.
저는 이것이 사실 Apple이 그들의 프레임워크에서 GC를 그만두고 자동 참조 카운팅을 선택한 것과 같은 이유라고 생각합니다.
- jacobgold
"이렇게 하면 아파요"
"그러면 그만 하세요"
지연 시간이 중요하다면 swap을 비활성화하세요. 시스템 전체든, 특정 cgroup이든.
- pizlonator
Go가 STW가 전혀 없는 on the fly GC를 사용하지 않는 이유가 있나요?
- xavdid
Discord는 2020년에 이 문제를 깨닫고 훌륭한 블로그 글을 발행했습니다: https://discord.com/blog/why-discord-is-switching-from-go-to...
- soltanov
GC 지연 시간 SLO에는 운영체제 메모리 압박이 포함되어야 합니다. 그렇지 않으면 페이지 폴트 문제가 컬렉터 문제처럼 보여서 잘못된 해결책으로 이어질 수 있습니다.
- Gabrys1
swap을 인지하는 GC가 가능할까 하는 생각이 들었습니다. 예를 들어 먼저 필요한 페이지를 swap in 시키고(그런 명확한 API가 있는 것도 아니지만...) 그 다음에야 세상을 멈추는 거죠?
- imclaren
이거죠. 메모리 비대화 버그는 Go에서 비교적 고치기 쉽지만, 때로는 swap 비대화를 제거하는 게 모험입니다. 그리고 저는 모든 swap 비대화를 제거할 가치가 있다고 생각합니다!
- faangguyindia
저는 Node, Ruby, Python을 쓸 자리에 Go를 씁니다.
낮은 지연 시간이 필요할 때는 Rust를 씁니다.