Bulkhead
Bulkhead는 하나의 서비스 안에서 자원 풀을 목적별로 나눠, 한 영역의 부하나 장애가 다른 영역의 용량까지 먹어 치우지 못하게 만드는 패턴입니다. 이름은 배의 격벽처럼 한 칸이 침수돼도 배 전체가 가라앉지 않게 막는 구조에서 왔습니다. 즉 이 패턴의 본질은 실패를 막는 것이 아니라, 실패가 퍼지는 범위를 미리 잘라 두는 것입니다.
▶아키텍처 다이어그램
🔍 구조 다이어그램점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다
서비스가 하나의 공용 스레드 풀, 공용 커넥션 풀, 공용 작업 큐를 쓰면 가장 느린 의존성이나 가장 무거운 요청이 전체 자원을 먼저 잠식합니다. 그 결과 보고서 생성 같은 비핵심 작업이 폭주했는데 결제 API까지 응답하지 않는 일이 벌어집니다. 장애는 특정 기능에서 시작됐는데, 실제 다운은 시스템 전체처럼 보이게 됩니다. 공유 자원이 곧 장애 전파 통로가 되는 셈입니다.
초기 웹 애플리케이션은 트래픽 패턴과 의존성이 상대적으로 단순해서 공용 풀 전략으로도 버틸 수 있었습니다. 하지만 외부 API 호출, 비동기 작업, 멀티테넌트 부하가 늘어나면서 일부 기능의 지연이 전체 애플리케이션 포화로 이어지는 사례가 많아졌습니다. 특히 클라우드 환경에서는 순간 부하가 급격하게 튀고, 하나의 느린 의존성이 수백 개 동시 요청을 묶어 두는 일이 흔했습니다. 이 환경에서 자원 자체를 나눠 보호해야 한다는 인식이 확산됐습니다.
실무에서는 의존성별 HTTP 커넥션 풀을 따로 두거나, 작업 종류별 워커 큐를 나누거나, 테넌트 그룹별 동시성 한도를 분리하는 식으로 구현합니다. 핵심은 모든 요청이 같은 병목 자원을 공유하지 않게 만드는 것입니다. 한 풀에서 포화나 오류가 발생해도 다른 풀에는 여유가 남아 있어 핵심 경로는 계속 처리할 수 있습니다. 이 구조는 단순히 제한을 거는 것이 아니라, 어떤 경로를 무엇으로부터 보호할지 먼저 정의하는 설계 작업입니다.
Circuit Breaker가 실패율과 타임아웃을 보고 호출 자체를 잠시 열고 닫는 보호 장치라면, Bulkhead는 애초에 자원 공간을 분리해 한쪽 고갈이 다른 쪽으로 넘어오지 못하게 합니다. 둘은 경쟁 관계가 아니라 서로 다른 층의 보호 장치입니다. Load Balancer가 요청을 여러 인스턴스로 퍼뜨려 인스턴스 수준 병목을 낮춘다면, Bulkhead는 하나의 인스턴스나 서비스 내부에서 경로별 자원 고갈을 막습니다.
결제, 로그인, 주문 생성처럼 반드시 지켜야 하는 핵심 경로와, 리포트 생성, 추천 계산, 외부 동기화처럼 느려져도 되는 경로가 한 서비스 안에 공존할 때 특히 중요합니다. 멀티테넌트 SaaS에서 대형 고객 한 곳의 부하가 전체 고객 경험을 무너뜨리지 않게 하는 데도 자주 쓰입니다. 다만 풀을 너무 잘게 나누면 유휴 자원이 늘고 운영이 복잡해지므로, 실제 장애 전파 경로를 관측한 뒤 필요한 곳에만 적용하는 것이 좋습니다.