동시성의 극한 속도: 거대한 큐 병목을 부순 LMAX Disruptor 링 버퍼 매커니즘
초고빈도 거래(HFT)를 다루는 가상 자산 오더북(Orderbook) 엔진을 자바로 개발하면서, BlockingQueue에 매수/매도 주문을 담아 스레드끼리 전달하는 구조를 짰더니 락(Lock) 경합만으로 처리 지연율이 밀리초를 우습게 돌파했습니다. 우리는 코드를 버리고 하드웨어 CPU의 레이아웃을 공부하기 시작했습니다. 그 방향의 끝에 영국의 LMAX 거래소가 고안해 낸 괴물 같은 프레임워크인 Disruptor가 있었습니다.
일반적인 큐(Queue)는 머리와 꼬리에 포인터를 가지고 있으며, 데이터를 넣고 뺄 때마다 멀티 스레드가 뮤텍스 락을 걸고 해제합니다. 더 끔찍한 것은 메모리 상에 객체가 파편화되어 할당되므로 CPU L1 캐시 히트율이 바닥을 친다는 것입니다. Disruptor는 큐를 가차 없이 버리고, 메모리에 한 덩어리로 붙어있는 거대한 원형 배열(Ring Buffer)을 미리 찍어내어 할당해 냅니다. 여기에 시퀀스 배리어(Sequence Barrier)라는 무식한 일련번호 체계 하나만을 둡니다.
생산자(Publisher) 스레드들은 배열의 자리를 선점하기 위해 락을 걸지 않고, CPU가 하드웨어 레벨에서 지원하는 CAS(Compare-And-Swap) 원자적 명령어 하나로 자신의 시퀀스 번호를 가로채 배열 칸을 확보합니다. 소비자는 그저 이전 시퀀스 번호의 작업이 끝났는지만 Spin-Wait(루프 대기)로 감시하며 미친 듯이 배열을 질주합니다. 게다가 캐시 라인(64바이트)이 CPU 코어 간에 겹치면서 무의미하게 강제 동기화되는 거짓 공유(False Sharing) 현상조차 막기 위해 양옆에 여백(Padding)을 8바이트씩 채워놓는 변태적인 최적성까지 발휘합니다. 자바의 JVM을 쓰고 있음에도 소프트웨어가 컴파일러를 넘어 실리콘 메모리 버스와 공감대(Mechanical Sympathy)를 맞추었을 때 터져 나오는 초당 수백만 트랜잭션의 락 프리(Lock-Free) 마법은 엔지니어링의 최고 예술이었습니다.
Related Posts
JVM JIT 컴파일러의 극단적 런타임 최적화: 탈출 분석(Escape Analysis)과 스칼라 치환의 마법
정적 컴파일 언어를 압도하는 자바 머신의 동적 스크립트 프로파일링 및 객체 힙 버림 최적화 기법.
리눅스 eBPF와 XDP를 활용한 커널 바이패스(Kernel Bypass) 초저지연 패킷 필터링 아키텍처
운영체제 네트워크 스택의 병목을 우회하여 디바이스 드라이버 레벨에서 직접 샌드박스 코드를 주입하는 eBPF의 혁명.
스플릿 브레인(Split-Brain) 붕괴를 막는 분산 락(Distributed Lock) 시스템과 펜싱(Fencing) 토큰의 도입
Zookeeper, Redis Redlock의 시계 위임 맹점을 찌르는 가비지 컬렉션 시간 정지(Stop-the-World) 현상 롤백 설계.