CS Insights

Golang 가비지 컬렉터(GC)의 한계 돌파: STW 정지를 막아내는 삼색 마크 앤 스위프와 Pacing 스케줄링

Golang 가비지 컬렉터(GC)의 한계 돌파: STW 정지를 막아내는 삼색 마크 앤 스위프와 Pacing 스케줄링
Java 서버를 Go(Golang)로 마이그레이션 한 후, 과거 수십 밀리초씩 얼어붙던 끔찍한 GC(Garbage Collection) Stop-The-World 현상이 감쪽같이 사라졌습니다. 모니터링 상 Go 서버의 GC 중단 시간은 고작 0.5 밀리초 미만이었습니다. 이 마법 같은 지연율의 비밀은 Go 언어 설계자들의 광적인 "백그라운드 동시성(Concurrent)" 철학에 있었습니다. Golang은 세대별(Generational) GC라는 복잡한 메모리 이주 방식을 과감히 버리고, 극도로 단순한 삼색(Tri-color) 마크 앤 스위프 방식을 선택했습니다. 가장 소름 돋는 점은 이 거대한 쓰레기 청소 과정이 유저의 로직과 동시에 맞물려 돈다는 것입니다. 하지만 쓰레기를 치우는 와중에 유저가 계속 쓰레기를 버리면(메모리 할당을 하면) 청소부 스레드가 이를 영원히 따라잡지 못하는 OOM 상태에 빠지게 됩니다. 이를 막기 위해 Go 스케줄러는 놀라운 꼼수, Pacing(속도 조절)과 Mark Assist 매커니즘을 발동합니다. 메모리 할당을 너무 미친 듯이 해대는 악성 고루틴(Goroutine)을 적발하면, OS 스케줄러는 이 고루틴의 실행 권한을 잠시 뺏어버립니다. 그리고는 "네가 싼 똥이 너무 많으니, 네가 직접 청소 좀 돕고 와라"라며 이 어플리케이션 고루틴을 강제로 GC 청소부 스레드로 징용시켜 버립니다. 유저의 프로세스가 스스로 GC 인프라에 노동력을 제공하게 만들어 메모리 펌핑 속도 자체를 물리적으로 브레이크 거는 것입니다. 백엔드 시스템은 단순히 빠른 것보다 예측 가능성(Predictability)이 더 중요하다는 언어적 패러다임을 처절하게 실감할 수 있었습니다.

Related Posts