REST API 리드·아키텍트 시스템 설계 면접
새 면접Q. 월간 1억 건 이상의 요청을 처리하는 공개 REST API 서비스에서 하위 호환성을 깨는 major 버전 업그레이드를 진행해야 합니다. URI 버저닝(/v1, /v2), 헤더 버저닝(Accept-Version), 쿼리 파라미터 버저닝 등 여러 방식 중 어떤 전략을 선택하시겠습니까? 각 방식의 트레이드오프와 함께 선택 근거를 설명해주세요.
캐싱 효율성, 클라이언트 마이그레이션 용이성, 운영 복잡도를 함께 고려해보세요.
공개 API의 경우 URI 버저닝(/v1, /v2)을 권장합니다. 가장 명시적이고 직관적이며, CDN 및 HTTP 캐시와의 호환성이 우수하고, API 문서화와 모니터링이 용이합니다. 헤더 버저닝은 REST 원칙에 더 부합하지만 디버깅이 어렵고 클라이언트 구현 실수 가능성이 높습니다. 다만 URI 버저닝은 라우팅 복잡도가 증가하므로 API Gateway에서 버전별 라우팅 규칙을 명확히 정의하고, Sunset 헤더를 활용해 구버전 deprecated 일정을 공지해야 합니다. 내부 API라면 헤더 버저닝도 고려할 수 있으나, 외부 파트너사가 있는 공개 API는 진입 장벽을 낮추는 것이 중요하므로 URI 버저닝이 최선입니다.
- • URI 버저닝이 명시성과 캐싱 효율성 측면에서 공개 API에 유리
- • 헤더 버저닝은 REST 원칙 준수하나 디버깅과 클라이언트 구현 난이도 높음
- • Sunset 헤더와 deprecation 정책으로 마이그레이션 관리 필요
Stripe, Twilio 같은 대규모 공개 API 서비스에서 여러 버전을 장기간 병행 운영하며 클라이언트 마이그레이션을 관리할 때 필수적인 의사결정입니다.
v1과 v2를 동시에 운영하는 기간 동안 코드 중복을 최소화하면서 각 버전을 독립적으로 배포할 수 있는 아키텍처 구조는 어떻게 설계하시겠습니까?
Q. 전국 매장 위치 정보를 제공하는 REST API를 설계 중입니다. 10만 개 이상의 매장 데이터가 있고, 사용자 위치 기반으로 반경 내 매장을 검색하는 GET /stores 엔드포인트를 설계해야 합니다. 페이지네이션 방식(offset-based, cursor-based, keyset), 응답 구조, 캐싱 전략, 지리 검색 최적화를 포함한 전체 설계 방안을 제시해주세요.
지리 데이터의 특성상 검색 조건이 동적이며, 사용자 위치에 따라 결과가 달라지는 점을 고려하세요.
위치 기반 검색은 결과가 동적이므로 cursor-based 페이지네이션을 권장합니다. offset-based는 데이터 변경 시 중복/누락 문제가 있고, 10만 건 이상에서 offset이 클수록 성능 저하가 심합니다. 쿼리 파라미터는 lat, lng, radius, cursor, limit를 받고, 응답에는 next_cursor와 has_more를 포함합니다. 지리 검색은 PostGIS나 Elasticsearch의 geo_distance 쿼리를 활용하고, 자주 검색되는 주요 지역은 Redis Geospatial 인덱스로 캐싱합니다. 매장 상세 정보는 CDN에 캐시하되, 위치 검색 결과는 TTL을 짧게(1-5분) 설정하거나 Cache-Control: private로 설정해 개인화된 결과를 보호합니다. ETag를 활용한 조건부 요청으로 변경되지 않은 매장 목록의 대역폭을 절약할 수 있습니다.
- • cursor-based 페이지네이션으로 대용량 데이터 안정적 탐색
- • PostGIS/Elasticsearch geo 쿼리와 Redis Geospatial 캐싱 조합
- • 개인화된 위치 검색 결과는 짧은 TTL 또는 private 캐시 설정
배달앱, 지도 서비스, 매장 찾기 기능에서 수십만 개 POI 데이터를 실시간으로 검색하고 페이지네이션하는 API 설계 시 필수적입니다.
동일한 위치에서 반복 검색하는 사용자가 많을 때, 개인정보 보호를 유지하면서도 캐시 hit rate를 높이려면 어떤 전략을 사용할 수 있을까요?
Q. MSA 환경에서 여러 서비스가 공통으로 사용하는 결제 API에 rate limiting을 구현해야 합니다. 사용자별, API 키별, IP별로 각각 다른 제한을 적용해야 하고, 분산 환경에서 정확한 카운팅이 필요합니다. Token Bucket, Leaky Bucket, Fixed Window, Sliding Window 알고리즘 중 어떤 것을 선택하시겠으며, 분산 환경에서의 구현 방안과 아키텍처를 설계해주세요.
결제 API는 순간적인 버스트 트래픽을 어느 정도 허용하면서도 전체 처리량을 제어해야 합니다.
결제 API는 순간 버스트를 허용하되 장기 평균을 제어해야 하므로 Token Bucket 알고리즘을 권장합니다. Sliding Window는 정확하나 메모리 사용량이 많고, Fixed Window는 경계에서 burst 문제가 있습니다. 분산 환경에서는 Redis를 중앙 저장소로 사용하고, Lua 스크립트로 토큰 소비와 재충전을 atomic하게 처리합니다. API Gateway 레벨에서 1차 체크(Kong, AWS API Gateway의 rate limiting 기능)를 하고, 서비스 레벨에서 2차 체크를 두어 defense in depth를 구현합니다. 사용자별/키별/IP별 제한은 Redis key 네이밍 전략(rate:user:{id}, rate:key:{key})으로 구분하고, 각각 다른 limit과 refill rate를 설정합니다. 429 응답 시 Retry-After 헤더와 X-RateLimit-* 헤더로 클라이언트에게 상태를 명확히 전달합니다.
- • Token Bucket으로 버스트 허용하면서 평균 처리량 제어
- • Redis + Lua 스크립트로 분산 환경에서 atomic한 카운팅 구현
- • API Gateway와 서비스 레벨의 2단계 rate limiting으로 방어
결제, 인증, SMS 발송 등 비용이 발생하거나 보안이 중요한 API에서 악의적 사용과 과도한 비용을 방지하기 위해 필수적입니다.
Redis가 일시적으로 장애가 발생했을 때 rate limiting을 어떻게 처리하시겠습니까? fail-open과 fail-closed 중 어떤 전략을 선택하시겠습니까?
Q. 전자상거래 플랫폼의 상품 상세 API를 설계합니다. 상품 기본 정보는 변경이 드물지만, 재고 수량과 가격은 실시간으로 변경됩니다. 또한 사용자별로 할인가가 다르게 표시됩니다. 이런 복합적인 요구사항에서 CDN 캐싱, 서버 캐싱, 클라이언트 캐싱을 어떻게 조합하여 설계하시겠습니까? Cache-Control, ETag, Vary 헤더 전략과 함께 설명해주세요.
데이터를 변경 빈도에 따라 분리하고, 개인화된 부분과 공통 부분을 구분하는 것이 핵심입니다.
API를 두 개로 분리합니다. GET /products/{id}는 기본 정보만 반환하고 Cache-Control: public, max-age=3600, s-maxage=86400으로 CDN에 장기 캐싱합니다. GET /products/{id}/dynamic은 재고와 가격을 반환하며 Cache-Control: private, max-age=60으로 짧게 캐싱하고, Vary: Authorization 헤더로 사용자별 응답을 구분합니다. 또는 단일 API로 구성 시 기본 정보는 응답 본문에, 동적 정보는 별도 필드로 분리하고 ETag를 상품 버전 해시로 생성해 조건부 요청을 지원합니다. 서버 측은 Redis에 상품 기본 정보를 캐시하고, 재고/가격은 별도 키로 관리하며 TTL을 10-30초로 짧게 설정합니다. GraphQL을 고려한다면 클라이언트가 필요한 필드만 요청하게 해 over-fetching을 방지할 수 있습니다. Stale-While-Revalidate 전략으로 캐시 만료 시에도 이전 데이터를 보여주며 백그라운드에서 갱신합니다.
- • 변경 빈도에 따라 API 분리 또는 응답 구조 계층화
- • 정적 데이터는 CDN 장기 캐싱, 동적 데이터는 짧은 TTL과 private 캐시
- • ETag와 Stale-While-Revalidate로 캐시 효율성과 신선도 균형
쿠팡, 11번가 같은 대규모 커머스에서 수백만 상품 API 응답 시간을 최소화하면서도 실시간 재고와 가격 정확성을 보장해야 할 때 필수적입니다.
프로모션으로 전체 상품 가격이 일괄 변경되는 경우, 캐시 무효화를 어떻게 처리하시겠습니까? Cache invalidation 전략을 설명해주세요.
Q. 10년 이상 운영된 SOAP 기반 레거시 시스템을 REST API로 전환하는 프로젝트를 리드합니다. 수백 개의 클라이언트가 기존 SOAP API를 사용 중이며, 한 번에 모두 전환할 수 없습니다. Strangler Fig 패턴을 적용하여 점진적 마이그레이션을 진행할 때, API Gateway 아키텍처, 라우팅 전략, 데이터 동기화, 롤백 계획을 포함한 전환 전략을 수립해주세요.
새 시스템과 구 시스템이 공존하는 기간 동안 데이터 일관성과 클라이언트 영향 최소화가 핵심입니다.
API Gateway를 파사드로 두고 클라이언트 요청을 SOAP/REST로 라우팅합니다. 초기에는 Gateway가 REST 요청을 받아 SOAP로 변환해 레거시를 호출하고, 점진적으로 기능별로 새 REST 서비스를 구축합니다. 라우팅은 feature flag나 클라이언트 헤더(X-API-Version)로 제어해 특정 클라이언트만 새 API를 사용하도록 카나리 배포합니다. 데이터베이스는 초기에는 공유하되, Change Data Capture(CDC)나 dual write 패턴으로 신구 시스템 간 동기화하고, 최종적으로는 database-per-service로 분리합니다. 각 기능 전환 시 shadow mode로 신구 시스템 응답을 비교 검증하고, 문제 발생 시 즉시 라우팅을 롤백할 수 있도록 feature flag를 준비합니다. 모니터링은 양쪽 시스템의 latency, error rate, throughput을 대시보드로 실시간 비교하며, 전환 진행률을 추적합니다.
- • API Gateway 파사드와 feature flag로 점진적 트래픽 전환
- • CDC나 dual write로 데이터 동기화하며 일관성 유지
- • shadow mode 검증과 즉시 롤백 가능한 라우팅 전략
금융, 통신, 대기업 SI 프로젝트에서 안정적으로 운영 중인 레거시를 무중단으로 현대화할 때 반드시 필요한 전략입니다.
SOAP의 트랜잭션 보장 기능(WS-Transaction)을 REST로 전환할 때 분산 트랜잭션을 어떻게 처리하시겠습니까? Saga 패턴 적용 방안을 설명해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!