NYO_O

분산 시스템의 단일 진입점과 공통 관심사 통제: API 게이트웨이(API Gateway) 아키텍처 본문

Architecture/MSA

분산 시스템의 단일 진입점과 공통 관심사 통제: API 게이트웨이(API Gateway) 아키텍처

NYO_O 2026. 5. 27. 07:04
반응형

클라이언트가 직면하는 분산 시스템의 복잡성

지금까지 우리는 백엔드 내부의 인프라 아키텍처를 탄탄하게 구축해 왔습니다. 마이크로서비스들은 서비스 디스커버리를 통해 동적으로 서로를 찾고, 로드 밸런서로 트래픽을 분산하며, 서킷 브레이커로 장애를 격리하고, Config 서버를 통해 설정값을 중앙에서 동기화합니다.

2026.05.27 - [Tech/MSA] - 파편화된 설정 정보의 중앙 집중화: Spring Cloud Config 아키텍처

 

파편화된 설정 정보의 중앙 집중화: Spring Cloud Config 아키텍처

수십 개의 application.yml이 만드는 배포 병목 현상지금까지 우리는 마이크로서비스 아키텍처(MSA)를 구성하는 핵심 통신 인프라들에 대해 알아보았습니다. 서비스들은 서비스 디스커버리를 통해

ddangnyo.tistory.com

하지만 시선을 백엔드 내부에서 외부의 '클라이언트(웹 브라우저, 모바일 앱)'로 돌려보면 전혀 다른 문제가 나타납니다. 마이크로서비스가 50개로 쪼개져 있다면, 클라이언트는 상품 목록을 불러오기 위해 '상품 서비스(10.0.1.5:8080)'를 호출하고, 결제를 위해 '결제 서비스(10.0.2.10:8081)'를 각각 다른 주소로 호출해야 할까요?

만약 그렇다면 클라이언트는 50개의 개별 도메인과 IP 주소를 모두 하드코딩하여 관리해야 합니다. 또한, 각 서비스마다 CORS(교차 출처 리소스 공유) 설정을 개별적으로 열어주어야 하며, 백엔드의 내부 인프라 구조가 변경될 때마다 클라이언트 앱을 무조건 새로 배포해야 하는 강한 결합(Tight Coupling)이 발생합니다. 이는 백엔드 아키텍처의 복잡성을 프론트엔드에게 고스란히 전가하는 안티 패턴입니다.

API 게이트웨이(API Gateway)의 등장과 단일 진입점(Single Entry Point) 역할

이러한 문제를 해결하기 위해 클라이언트와 백엔드 마이크로서비스 그룹 사이에 위치하는 리버스 프록시(Reverse Proxy) 계층을 도입하게 되며, 이를 'API 게이트웨이(API Gateway)'라고 부릅니다.

디자인 패턴 중 '파사드 패턴(Facade Pattern)'과 유사한 역할을 하는 API 게이트웨이는 시스템의 단일 진입점(Single Entry Point)으로 동작합니다. 클라이언트는 백엔드 내부에 50개의 서비스가 있는지 100개의 서비스가 있는지 알 필요가 없습니다. 오직 API 게이트웨이의 단일 도메인(예: api.gupang.com)으로만 모든 요청을 보냅니다.

요청을 받은 API 게이트웨이는 요청의 URL 경로(Path)나 헤더(Header) 정보를 분석하여, 백엔드 내부의 적절한 마이크로서비스로 트래픽을 라우팅(Routing)합니다. 이때 앞선 포스팅에서 배운 '서비스 디스커버리(Eureka 등)'와 연동하여, 고정된 IP가 아닌 서비스의 '이름'을 기반으로 동적인 라우팅과 로드 밸런싱을 수행합니다. 이로써 백엔드의 복잡한 내부 구조를 클라이언트로부터 완벽하게 캡슐화(Encapsulation)할 수 있게 됩니다.

공통 관심사(Cross-Cutting Concerns)의 분리

API 게이트웨이는 단순히 트래픽을 전달하는 길잡이 역할만 하는 것이 아닙니다. 50개의 마이크로서비스가 공통으로 수행해야 하는 기능들을 게이트웨이 계층으로 끌어올려 처리하는 '공통 관심사(Cross-Cutting Concerns)의 분리'야말로 가장 중요한 존재 이유 중 하나입니다.

대표적인 공통 관심사는 다음과 같습니다.

  • 인증 및 인가 (Authentication/Authorization): 클라이언트가 보낸 JWT 토큰이 유효한지 검증하는 로직을 50개의 서비스에 각각 구현할 필요가 없습니다. 게이트웨이에서 토큰을 한 번 검증하고, 유효한 요청만 내부 서비스로 통과시킵니다.
  • 비율 제한 (Rate Limiting): 특정 클라이언트나 IP가 비정상적으로 많은 요청을 보내 시스템을 마비시키는 것을 막기 위해, 게이트웨이 단에서 초당 요청 횟수를 제한합니다.
  • CORS 및 로깅 처리: 외부 브라우저를 위한 CORS 헤더 세팅과 모든 API 요청에 대한 진입/진출 로깅을 한 곳에서 통제합니다.

이처럼 공통 로직을 게이트웨이로 위임하면, 개별 마이크로서비스의 개발자들은 인프라적인 고민을 덜어내고 오직 순수한 비즈니스 로직(도메인 로직) 구현에만 집중할 수 있게 됩니다.

BFF(Backend for Frontend) 패턴으로의 아키텍처 확장

API 게이트웨이 하나로 모든 외부 요청을 처리하다 보면, 모바일 앱을 위한 API와 웹 브라우저를 위한 API 요구사항이 달라 게이트웨이가 비대해지는 현상이 발생할 수 있습니다. 예를 들어, 모바일은 데이터 절약을 위해 요약된 상품 정보를 원하고, PC 웹은 고해상도 이미지와 상세 정보를 한 번에 원할 수 있습니다.

이때 단일 게이트웨이의 부담을 줄이기 위해 클라이언트의 유형별로 게이트웨이를 여러 개로 분리하는 아키텍처를 BFF(Backend for Frontend) 패턴이라고 합니다. 모바일 전용 BFF, 웹 전용 BFF를 따로 두어 각 클라이언트에 최적화된 API 조합(Aggregation)과 데이터 포맷팅을 제공함으로써, 게이트웨이 계층의 유연성과 유지보수성을 한 단계 더 끌어올릴 수 있습니다.

Spring Cloud Gateway와 논블로킹(Non-Blocking) I/O

자바 기반의 MSA 생태계에서 과거에는 넷플릭스의 Zuul이 널리 쓰였으나, 현재는 Spring Cloud Gateway(SCG)가 사실상의 표준으로 사용되고 있습니다.

API 게이트웨이는 시스템의 모든 트래픽이 지나가는 관문이기 때문에 병목(Bottleneck)이 발생하기 가장 쉬운 지점입니다. 톰캣(Tomcat) 기반의 스레드 풀 모델을 사용하던 기존의 방식은 수만 건의 동시 접속이 발생하면 스레드가 고갈되는 치명적인 한계가 있었습니다.

Spring Cloud Gateway는 이를 극복하기 위해 Spring WebFlux와 Netty 기반의 비동기 논블로킹(Asynchronous Non-Blocking) I/O 모델을 채택했습니다. 소수의 스레드만으로도 엄청난 양의 동시 요청을 차단 없이(Non-blocking) 효율적으로 라우팅할 수 있어, 대규모 MSA 트래픽의 단일 진입점 역할을 수행하기에 최적화된 성능을 자랑합니다.

마무리

오늘은 복잡한 백엔드 시스템을 클라이언트로부터 숨겨주고, 인증과 라우팅 등 시스템 전체의 공통 관심사를 최전선에서 통제하는 방어선인 API 게이트웨이 아키텍처에 대해 알아보았습니다. 이제 클라이언트는 단일 도메인으로 편리하게 요청을 보내고, 백엔드 서비스들은 안전하게 보호받으며 자신의 비즈니스에만 집중할 수 있게 되었습니다.

이로써 인프라 레벨의 굵직한 아키텍처 요소들은 대부분 자리를 잡았습니다. 하지만 시스템이 분산될수록 새롭게 떠오르는 가장 무서운 악몽이 하나 있습니다.

클라이언트가 게이트웨이로 보낸 하나의 결제 요청이 내부적으로 주문 서비스 → 재고 서비스 → 결제 서비스 → 배송 서비스 순서로 4번이나 네트워크를 타고 넘어갔다고 가정해 보겠습니다. 그런데 3번째인 결제 서비스 어딘가에서 NullPointerException이 발생해 전체 요청이 실패했습니다. 50대의 서버에 흩어져 있는 수천만 줄의 로그 더미 속에서, 이 특정 사용자의 요청이 지나간 궤적만을 정확히 발라내어 에러 원인을 추적할 수 있을까요?

다음 포스팅에서는 분산 시스템의 트러블슈팅을 위한 한 줄기 빛, 흩어진 로그를 하나로 꿰어주는 '분산 추적(Distributed Tracing)' 아키텍처에 대해 자세히 다루어 보겠습니다.

반응형