API 안정성 설계 (보호계층, 장애방지, 관측체계)

API 안정성은 단일 기술로 해결되는 문제가 아닙니다. 다양한 전략과 패턴이 결합되어야 비로소 안정적인 시스템을 구축할 수 있습니다. 지금까지 살펴본 다양한 요소들은 각각 독립적인 기능이 아니라, 서로 연결된 구조를 형성합니다. 이 글에서는 API 안정성을 구성하는 핵심 요소를 종합적으로 정리하고, 실무에서 반드시 구축해야 하는 기준을 제시합니다. 서비스가 갑자기 죽었을 때 가장 먼저 드는 생각은 "왜 미리 못 잡았지?"입니다. 저도 새벽에 슬랙 알림을 받고 노트북을 열었던 기억이 있습니다. 알고 보니 외부 결제 API 하나가 느려지면서 연결을 잡고 놓지 않아 전체 서버 스레드가 고갈된 케이스였습니다. Rate Limiting도 없었고, Timeout 설정도 기본값 그대로였습니다. 그때 처음으로 API 안정성 설계가 단순한 '선택 사항'이 아니라는 걸 몸으로 배웠습니다. 기본 보호 계층, 왜 설정하지 않는가 Rate Limiting, Timeout, Retry. 이 세 가지는 API 안정성의 가장 기초적인 보호 계층입니다. Rate Limiting은 단위 시간 내에 허용할 요청 수를 제한하는 방식으로, 트래픽 급증이나 악의적인 과부하 공격으로부터 서버를 지킵니다. Timeout은 응답을 기다리는 최대 시간을 설정하는 것인데, 이게 없으면 느린 외부 서비스 하나가 커넥션 풀 전체를 잠가버릴 수 있습니다. Retry는 일시적 오류에 대해 요청을 자동으로 재시도하는 전략입니다. 그런데 여기서 주의할 점이 있습니다. Retry를 아무 생각 없이 붙이면 오히려 장애를 악화시킵니다. 이미 느린 서버에 재시도가 폭주하면 부하가 기하급수적으로 올라가기 때문입니다. 그래서 Exponential Backoff, 즉 재시도 간격을 점점 늘려가는 방식과 함께 써야 효과가 납니다. 이 조합을 적용하고 나서 저희 팀에서 일시적 오류로 인한 실패율이 체감상 절반 이하로 줄었습니다. 일반적으로 이 설정들은 기본값으로도 충분하다고 생각하는 분...

API Partial Response (네트워크 절감, 구현 복잡성, 캐시 전략)

사용자 프로필 API를 운영하던 중에 모바일 팀에서 "화면에 이름이랑 프로필 사진만 쓰는데 왜 이렇게 데이터가 많이 내려와요?"라는 질문을 받았던 적이 있습니다. 당시 API는 사용자 정보 전체를 한 번에 쏟아내고 있었죠. 그때 처음 고민하게 된 게 바로 API Partial Response 전략이었습니다. 필요한 데이터만 선택적으로 요청하고 받을 수 있다면 네트워크 부담을 확 줄일 수 있을 것 같았거든요. 그런데 막상 적용하려고 보니 생각보다 고려할 게 많더군요.

네트워크 절감

API Partial Response란 클라이언트가 필요한 데이터 필드만 지정해서 요청할 수 있도록 하는 설계 방식을 말합니다. 쉽게 말해 전체 메뉴판 중에서 먹고 싶은 것만 골라서 주문하는 것과 비슷하다고 보면 됩니다. 일반적인 API 구조에서는 정해진 응답 형식을 항상 동일하게 반환하는데, 이 방식은 클라이언트마다 필요한 정보가 다를 때 불필요한 데이터까지 함께 전송되는 문제가 생깁니다.

제가 직접 측정해봤을 때 프로필 API의 경우 전체 응답 크기가 약 15KB였는데, 이름과 프로필 이미지 URL만 요청하도록 바꾸니 2KB 정도로 줄어들었습니다. 특히 모바일 환경에서는 이런 차이가 체감 속도로 이어지더군요. 데이터 요금제를 쓰는 사용자 입장에서도 불필요한 데이터 소모가 줄어드는 효과가 있었습니다. 국내 주요 포털의 모바일 API 최적화 사례를 보면(출처: 한국정보통신기술협회) 평균 30~40%의 트래픽 절감 효과를 보고하고 있습니다.

솔직히 처음에는 "이 정도 차이가 큰 의미가 있을까?" 싶었는데, 실제 서비스 환경에서 하루 수백만 건의 API 호출이 발생하는 상황이라면 이야기가 달라집니다. 누적 트래픽 비용 측면에서도 무시할 수 없는 규모가 되더군요.

구현 복잡성

네트워크 효율은 좋았지만 서버 개발자 입장에서는 머리가 아파지기 시작했습니다. 기존에는 정해진 구조만 반환하면 됐는데, 이제는 요청마다 다른 필드 조합을 처리해야 했으니까요. 동적 응답 생성(Dynamic Response Generation)이라는 개념인데, 요청받은 필드 목록에 따라 실시간으로 응답 구조를 만들어내는 로직이 필요합니다.

우리 팀에서는 처음에 간단하게 if 문으로 분기 처리를 하려고 했다가 필드 조합이 기하급수적으로 늘어나면서 코드가 감당이 안 되는 지경에 이르렀습니다. 결국 리플렉션(Reflection) 기법을 활용해서 요청된 필드명을 기준으로 객체에서 값을 추출하는 방식으로 재설계했죠. 이 과정에서 단위 테스트 케이스도 몇 배로 늘어났고, 예외 처리 로직도 훨씬 복잡해졌습니다.

또 하나 예상 밖이었던 건 데이터베이스 쿼리 최적화 문제였습니다. 필드별로 조인(Join)이 필요한 테이블이 다르다 보니, 요청된 필드에 따라 쿼리 자체를 동적으로 구성해야 했거든요. 필요 없는 테이블까지 조인하면 오히려 성능이 떨어지기 때문에, 쿼리 빌더(Query Builder) 로직도 함께 개선해야 했습니다. 개발 공수가 예상보다 2배 이상 늘어난 건 솔직히 부담이었습니다.

캐시 전략

구현 복잡성보다 더 골치 아팠던 건 캐시 전략이었습니다. 캐시 무효화(Cache Invalidation)란 저장된 캐시 데이터가 더 이상 유효하지 않을 때 이를 제거하거나 갱신하는 과정을 말하는데, Partial Response 환경에서는 이게 정말 복잡해집니다. 같은 사용자 정보라도 요청하는 필드 조합에 따라 응답이 달라지니 캐시 키(Cache Key)를 어떻게 설계할지부터 고민이었죠.

처음에는 "사용자 ID + 요청 필드 목록"을 조합해서 캐시 키를 만들었는데, 필드 순서만 달라져도 다른 캐시로 인식되는 바람에 캐시 히트율(Hit Rate)이 형편없었습니다. 필드 목록을 정렬해서 정규화하는 로직을 추가했지만, 여전히 같은 데이터를 여러 조합으로 중복 저장하는 비효율이 남아있었습니다. 결국 자주 요청되는 필드 조합만 선별해서 캐싱하는 선택적 캐시 전략으로 방향을 잡았습니다.

Partial Response를 도입한다면 캐시 정책을 처음부터 함께 설계하는 게 중요합니다. 나중에 추가하려고 하면 이미 복잡해진 응답 생성 로직과 엮이면서 리팩토링 범위가 걷잡을 수 없이 커지더군요. 실제로 국내 대형 커머스 플랫폼의 API 운영 사례를 보면(출처: 정보통신기획평가원) 캐시 설계 없이 Partial Response만 먼저 도입했다가 성능 문제로 재설계한 경우가 적지 않습니다.

적용 판단 기준

그렇다면 Partial Response 전략은 언제 적용하는 게 좋을까요? 아래 조건을 체크해보시길 권합니다.

  1. 모바일 환경이나 네트워크 제약이 있는 클라이언트 비중이 높은가
  2. 응답 데이터 크기가 10KB 이상으로 크고, 클라이언트마다 필요한 필드가 명확히 다른가
  3. 서버 개발 리소스와 시간이 충분히 확보되어 있는가
  4. 캐시 전략을 함께 설계할 수 있는 여유가 있는가

우리 팀 경험을 돌이켜보면, 사용자 프로필처럼 데이터 구조가 크고 클라이언트별 사용 패턴이 확연히 다른 API에서는 확실히 효과가 있었습니다. 반면 응답 크기가 작거나 대부분의 클라이언트가 비슷한 필드를 요청하는 경우라면 굳이 복잡성을 감수할 필요는 없다고 봅니다. 일반적으로 GraphQL 같은 쿼리 언어를 도입하는 방법도 있지만, 이 역시 학습 곡선과 인프라 구축 비용이 만만치 않습니다.

개인적으로는 신규 서비스라면 초기에는 단순한 REST API로 시작하고, 실제 트래픽 패턴을 분석한 뒤 병목이 명확할 때 Partial Response를 선택적으로 적용하는 게 현실적이라고 생각합니다. 처음부터 모든 API에 적용하려다가 개발 일정만 늘어지는 경우를 여러 번 봤거든요.

결국 Partial Response는 만능 해결책이 아니라 상황에 맞는 선택지 중 하나입니다. 네트워크 효율을 얻는 대신 구현 복잡성과 캐시 관리 부담을 떠안게 되는 트레이드오프(Trade-off) 관계라는 점을 명확히 인식하고 접근하시길 바랍니다. 다음 프로젝트에서는 주요 API 2~3개만 선별해서 적용해볼 생각입니다. 전체보다는 효과가 큰 곳에 집중하는 게 더 현명한 선택이라고 판단했거든요.

댓글

이 블로그의 인기 게시물

HTTP 메서드의 필요성 (GET과 POST, PUT과 DELETE, API 보안)

API 없는 세상의 불편함 (로그인 연동, 서비스 구조, 디지털 인프라)

API 이해하기 (서비스 연결, 시스템 협력, 디지털 구조)