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
JVM JIT 컴파일러의 극단적 런타임 최적화: 탈출 분석(Escape Analysis)과 스칼라 치환의 마법
정적 컴파일 언어를 압도하는 자바 머신의 동적 스크립트 프로파일링 및 객체 힙 버림 최적화 기법.
리눅스 eBPF와 XDP를 활용한 커널 바이패스(Kernel Bypass) 초저지연 패킷 필터링 아키텍처
운영체제 네트워크 스택의 병목을 우회하여 디바이스 드라이버 레벨에서 직접 샌드박스 코드를 주입하는 eBPF의 혁명.
스플릿 브레인(Split-Brain) 붕괴를 막는 분산 락(Distributed Lock) 시스템과 펜싱(Fencing) 토큰의 도입
Zookeeper, Redis Redlock의 시계 위임 맹점을 찌르는 가비지 컬렉션 시간 정지(Stop-the-World) 현상 롤백 설계.