MSA의 문지기, API Gateway - 구현부터 모니터링까지
1. 프롤로그 - "로그인이 5번 호출되는 악몽"
모놀리식(Monolithic)에서 마이크로서비스(MSA)로 전환하던 초창기, 저는 큰 실수를 저질렀습니다.
서비스를 Auth, User, Product, Order, Payment 5개의 마이크로서비스로 쪼갠 것까지는 좋았습니다.
문제는 프론트엔드에서 이 서비스들을 직접 호출하게 만든 것입니다.
어느 날 앱을 켰는데 로딩이 너무 느려서 네트워크 탭을 열어봤습니다.
메인 화면 하나를 그리기 위해 앱이 User 서버, Product 서버, Promotion 서버 등 5곳에 동시에 요청을 보내고 있었습니다. 더 끔찍한 건, 각 요청마다 인증 토큰을 검증하느라 Auth 서버가 5배로 고통받고 있었다는 점입니다. 게다가 어떤 서비스는 http로, 어떤 서비스는 https로 호출하고 있어 보안 경고창까지 뜨고 있었습니다.
"손님이 호텔 방(객실)에 들어가려고 하는데, 청소부, 요리사, 관리인에게 각각 열쇠를 보여주고 허락을 받는 꼴이구나."
이 혼란을 정리해줄 존재, 즉 "호텔 프론트 데스크"가 절실히 필요했습니다. 그것이 바로 API Gateway였습니다.
2. API Gateway란 무엇인가?
API Gateway는 클라이언트(손님)와 수많은 백엔드 서비스(호텔 직원들) 사이에 위치하는 "단일 진입점(Single Entry Point)"입니다. 단순히 문만 열어주는 것이 아니라, 들어오는 모든 요청을 검사하고, 적절한 곳으로 안내하며, 나가는 응답까지 책임지는 '지배인' 역할을 합니다.
핵심 역할 - 호텔 프론트 데스크의 4가지 임무
-
라우팅 (Routing): "체크인은 어디서 해요?"
- 클라이언트는 오직
api.hotel.com하나만 알면 됩니다. /users로 들어오는 요청은User Service로,/orders는Order Service로 내부에서 조용히 전달(Proxy)합니다.- 서비스의 IP가 바뀌거나 서버가 이사를 가도, 클라이언트는 알 필요가 없습니다.
- 클라이언트는 오직
-
인증 및 인가 (AuthN & AuthZ): "예약 문자 보여주세요."
- Offloading(짐 덜어주기): 문지기가 신분증(JWT Token)을 한 번만 검사하면, 안쪽의 직원(Service)들은 신분 검사를 안 해도 됩니다.
- 각 마이크로서비스마다 "로그인 검증 로직"을 넣는 중복 코드를 획기적으로 줄여줍니다.
-
속도 제한 (Rate Limiting): "단체 손님은 줄 서세요."
- 특정 IP가 1초에 100번 요청을 보내면, 문지기가 "잠깐만요" 하고 막아줍니다.
- DDoS 공격 방어뿐만 아니라, 특정 등급(유료/무료) 회원별로 API 사용량을 제어하는 비즈니스 로직으로도 쓰입니다.
-
부하 분산 (Load Balancing): "1번 창구 바쁘니까 2번으로 가세요."
User Service가 3대 떠 있다면, Gateway가 Round-Robin 방식 등으로 요청을 골고루 분배합니다.
3. 깊게 파고들기 - 핵심 기능 구현 원리
단순히 "연결해주는 것"을 넘어, API Gateway가 시스템의 안정성을 어떻게 책임지는지 기술적으로 파고들어봤다.
1) Rate Limiting (속도 제한) 알고리즘의 세계
서버가 터지는 것을 막기 위해 가장 중요한 기능입니다. 단순히 "많이 보내면 막는다"가 아닙니다. "1분에 60회 요청 가능" 같은 규칙을 구현하는 알고리즘은 생각보다 정교합니다.
-
Token Bucket (토큰 버킷)
- 원리: 버킷에 1초마다 토큰이 1개씩 떨어집니다. 요청이 들어올 때마다 토큰을 하나씩 가져갑니다. 토큰이 없으면 요청은 거절(429 Too Many Requests)됩니다.
- 장점: 순간적인 트래픽 폭주(Burst)를 허용합니다. 토큰이 10개 모여 있으면, 0.1초 만에 10번을 호출해도 됩니다.
- 사용처: AWS API Gateway, 일반적인 사용자 중심 REST API.
-
Leaky Bucket (구멍 난 양동이)
- 원리: 구멍 뚫린 양동이에 물(요청)을 붓습니다. 물이 아무리 많이 쏟아져도 구멍으로는 ‘똑… 똑…’ 정해진 속도로만 물이 나갑니다.
- 장점: 처리 속도를 일정하게 유지합니다(Traffic Smoothing). 서버 부하를 예측 가능하게 만듭니다.
- 사용처: Nginx (
limit_req_zone), 패킷 처리 네트워크 장비, 엄격한 SLA가 필요한 경우.
-
Fixed Window vs Sliding Window
- Fixed: "12:00 ~ 12:01 사이에 100개". 함정은 12:00:59에 100개, 12:01:01에 100개를 보내면 2초 만에 200개가 들어와 서버가 터질 수 있습니다.
- Sliding: 시간 창을 미끄러지듯 이동시켜서 위 문제를 방지합니다. Redis의 Sorted Set 등을 이용해 구현하며 가장 정확하지만 비용이 듭니다.
2) Security (보안) - 최전방 방어선
Gateway는 성문의 수문장입니다. 여기서 뚫리면 내부 서비스는 다 털립니다.
- WAF (Web Application Firewall): SQL Injection이나 XSS 같은 해킹 시도 패턴을 Gateway 레벨에서 감지하고 차단합니다. "User-Agent가 이상하다?" 혹은 "쿼리 파라미터에
DROP TABLE이 있다?" 바로 차단합니다. - IP Whitelist/Blacklist: 특정 국가나 악성 IP 대역을 원천 봉쇄합니다. 관리자 페이지(
/admin)는 사내 IP에서만 접속되게 설정할 수도 있습니다. - SSL Termination: HTTPS 암호화를 Gateway에서 풀고, 내부망에서는 HTTP로 통신합니다. 암호화/복호화는 CPU를 많이 먹는 작업인데, 이걸 Gateway가 전담함으로써 내부 서버들의 부하를 줄여줍니다.
3) Circuit Breaker (회로 차단기)와 장애 격리
User Service가 DB 과부하로 죽었다고 가정해봤다. 사용자는 계속 "로그인" 버튼을 누릅니다. Gateway는 죽은 서비스에 요청을 보내고 타임아웃(30초)까지 기다립니다. 대기하는 스레드가 쌓이면서 결국 Gateway까지 멈추고, 전체 서비스가 다운됩니다(Cascading Failure).
이때 Circuit Breaker가 작동합니다.
- Open: "어?
User Service쪽 응답이 5번 연속 실패했네? 전기 끊어!" (회로 열림) - Fail Fast: 이제
User Service로 가는 요청은 아예 보내지도 않고 즉시 에러("점검 중")를 리턴합니다. - Half-Open: 일정 시간이 지난 후, 슬쩍 요청 하나를 보내봅니다. "살아났니?"
- Closed: 살아났으면 다시 정상적으로 연결합니다.
이 패턴은 Netflix의 Hystrix, Java의 Resilience4j 등을 통해 유명해졌고, 이제는 Gateway의 필수 기능입니다.
4. 확장된 고민 - GraphQL과 Observability
1) GraphQL과 Gateway의 관계
요즘 프론트엔드에서 GraphQL을 많이 씁니다. 그럼 Gateway는 필요 없을까요? 오히려 GraphQL Gateway(Federation)가 중요해집니다.
- Schema Stitching/Federation:
User Service,Product Service가 각각 작은 GraphQL 스키마를 가지고 있고, Gateway가 이를 하나로 합쳐서(Stitching) 클라이언트에게는 하나의 거대한 API처럼 보여줍니다. - Apollo Federation이 대표적인 예시입니다. Gateway가 쿼리를 분석해서("이건 User 거, 저건 Product 거") 각 서비스에 쿼리를 날리고 결과를 조합해서 줍니다.
2) Observability (관측 가능성)
MSA의 단점은 "도대체 에러가 어디서 난 거야?"를 찾기 힘들다는 점입니다. Gateway는 모든 요청이 지나가는 길목이므로, 여기서 Tracing ID(Request ID)를 발급해야 합니다.
- Gateway가 요청에
X-Request-ID: abc-123헤더를 붙입니다. - 이 헤더는
Service A->Service B->DB까지 계속 따라다닙니다. - 나중에 로그 시스템(ELK, Datadog)에서
abc-123만 검색하면 전체 흐름이 한눈에 보입니다. 이것이 Distributed Tracing(분산 추적)의 시작입니다.
5. 도구 비교: Nginx vs Kong vs AWS API Gateway
그럼 뭘 써야 할까요? 제가 실제로 겪은 기준과 특징 비교입니다.
| 특징 | Nginx (Reverse Proxy) | Kong (API Gateway) | AWS API Gateway (Managed) |
|---|---|---|---|
| 정체성 | 고성능 웹 서버 / 프록시 | Oauth2, Rate Limit 등 API 관리에 특화된 Nginx 기반 오픈소스 | AWS가 관리해주는 완전 관리형 클라우드 서비스 |
| 확장성 | Conf 파일 수정 (정적) | Plugin 시스템 (동적)으로 기능 추가 용이 | 클릭 몇 번으로 설정 (동적), Lambda와 찰떡궁합 |
| 기능 | LB, Caching, Basic Auth 등 기본기 충실 | + Oauth2, JWT, Rate Limit, Monitoring, Logging | + 서버리스 연동, 사용량 과금, AWS IAM 연동 |
| 운영 난이도 | 상 (직접 스크립트 작성 및 튜닝 필요) | 중 (Admin API 제공, DB 필요) | 하 (GUI 제공, 하지만 복잡한 설정은 공부 필요) |
| 비용 | 무료 (오픈소스) | 무료 (오픈소스) / 유료 (엔터프라이즈) | 요청 건수당 과금 (비쌀 수 있음) |
| 추천 상황 | 단순한 라우팅만 필요하거나 성능이 최우선일 때 | On-Premise 환경, 커스텀 Plugin이 필요할 때 | 초기 스타트업, 서버 관리하기 싫을 때, AWS 생태계 |
제 선택: 초기 스타트업 단계에서는 AWS API Gateway가 압도적으로 편했습니다. 관리 이슈가 “0”에 가까웠으니까요. 하지만 트래픽이 월 1억 건을 넘어가면서 비용이 부담되기 시작했고, 결국 EC2 위에 Kong을 올려서 직접 운영하는 방식으로 전환하여 비용을 80% 절감했습니다.
6. BFF 패턴 (Backend For Frontend)
Gateway를 하나로 통일하다 보면, "모바일 앱"팀과 "웹 관리자"팀이 싸우게 됩니다.
- 앱: "데이터 줄여줘요. 썸네일만 주세요. JSON으로요."
- 웹: "상세 정보 다 주세요. 원본 이미지 주세요. XML도 필요해요."
이때 BFF (Backend For Frontend) 패턴이 등장합니다. 하나의 거대한 만능 Gateway(One strict gate) 대신, Client별로 전용 Gateway를 두는 전략입니다.
Mobile Gateway: 모바일에 최적화된 데이터만 모아서, 모바일 팀이 관리합니다.Web Gateway: 웹에 필요한 데이터를 모아서, 웹 팀이 관리합니다.
이렇게 하면 "프론트엔드 변경 때문에 백엔드 전체를 수정해야 하는" 강한 결합(Coupling)을 끊을 수 있습니다.
7. 요약
API Gateway가 없는 MSA는 "신호등 없는 8차선 사거리"와 같습니다. 처음에는 차가 몇 대 없어서 "빠르고 좋은데?"라고 생각할 수 있지만, 서비스가 커지고 트래픽이 늘어나면 반드시 대형 사고가 납니다.
- 인증/인가 중앙화: 문지기에게 신분증 검사를 전담시켜 중복 개발을 막아라.
- Rate Limiting: 악성 사용자나 트래픽 폭주로부터 서버를 보호하라.
- Circuit Breaker: 한 서비스의 장애가 전체 시스템의 장애로 번지는 것을 차단하라.
- Observability: 들어오는 모든 요청에 꼬리표(Trace ID)를 붙여서 추적하라.
이 4가지만 기억해도, 여러분의 MSA는 훨씬 안전하고 견고해질 것입니다.