API 응답 속도 (서버 점검, DB 최적화, 캐싱 전략)

API 응답 속도 저하는 사용자 경험을 직접적으로 악화시키는 핵심 문제 중 하나입니다. 응답 시간이 길어지면 사용자는 서비스가 느리다고 인식하게 되며, 이는 이탈률 증가와 서비스 신뢰도 하락으로 이어질 수 있습니다. API 응답이 느려졌을 때, 그냥 서버를 재시작하면 해결될 거라고 생각합니다. 그러나 재시작 후 10분도 안 돼서 똑같이 느려졌고, 원인을 찾는 데 반나절이 걸렸습니다. API 응답 속도 문제는 하나의 원인이 아니라 서버, DB, 네트워크가 뒤엉켜서 발생하는 경우가 대부분입니다. 이 글은 그 삽질을 줄이기 위한 점검 순서를 정리한 것입니다. 서버 점검, 어디서부터 봐야 할까요 API가 느려졌다는 신고를 받으면 가장 먼저 뭘 확인하시나요? 초반에 무조건 로그부터 뒤졌는데, 사실 그보다 먼저 봐야 할 게 있습니다. 바로 서버의 CPU 사용률과 메모리 점유율입니다. CPU 사용률이 80% 이상을 지속적으로 유지하고 있다면, 요청 하나하나를 처리하는 데 이미 자원이 부족한 상태입니다. 메모리도 마찬가지입니다. 가용 메모리가 거의 없으면 운영체제가 디스크 스왑(swap, 부족한 메모리를 디스크로 대신 사용하는 방식)을 시작하는데, 이 순간부터 응답 속도는 눈에 띄게 떨어집니다. 스왑이 발생하는 서버에서는 평균 응답 시간이 평소의 3배 이상 늘어났습니다. 그 다음은 스레드 풀(Thread Pool) 상태입니다. 스레드 풀이란 서버가 동시에 처리할 수 있는 요청 작업자의 수를 미리 정해둔 것인데, 들어오는 요청 수가 이 한도를 넘으면 나머지 요청은 줄을 서서 기다리게 됩니다. 이 대기 시간이 응답 지연으로 직결됩니다. 이런 구조에서는 스레드 수를 늘리거나, 비동기 처리 방식으로 전환하는 것이 현실적인 해결책입니다. 애플리케이션 내부 로직도 빠뜨리면 안 됩니다. 특히 반복문 안에서 외부 API를 호출하거나 DB 쿼리를 실행하는 구조가 있다면, 요청 1건에 수십 번의 외부 호출이 발생할 수 있습니다. 이건 코드 리뷰에서도 쉽게 놓치는 부분이라 따로 ...

API Mocking 전략 (병렬 개발, 검증 한계, 실무 적용)

API Mocking 전략은 실제 서버가 완전히 구현되지 않은 상태에서도 API 응답을 시뮬레이션하여 개발과 테스트를 진행할 수 있도록 하는 방식입니다. 클라이언트와 서버가 동시에 개발되는 환경에서는 한쪽이 완성될 때까지 다른 쪽이 대기해야 하는 문제가 발생할 수 있습니다. 이러한 병목을 해결하기 위해 Mocking이 도입되며, 가상의 응답 데이터를 통해 개발을 병렬로 진행할 수 있도록 합니다. 

 백엔드 API가 아직 안 나왔는데 프론트엔드 개발을 멈출 수는 없는 상황, 개발하다 보면 꽤 자주 맞닥뜨리게 됩니다. 그래서 API Mocking을 제대로 써보기 시작했고, 그 이후로 팀 전체 개발 흐름이 꽤 달라졌습니다. 다만 써보면서 "이건 좀 조심해야겠다" 싶은 지점도 분명히 생겼습니다.

병렬 개발: API 없이도 개발이 돌아가는 구조

API Mocking이란 실제 서버가 없는 상태에서 미리 정의된 응답 데이터를 반환하는 가짜 API를 만들어 개발과 테스트를 진행하는 방식입니다. 서버가 실제로 구현되지 않아도 클라이언트 입장에서는 진짜 API와 동일한 인터페이스로 작업할 수 있기 때문에, 프론트엔드와 백엔드가 서로를 기다릴 필요가 없어집니다.

직접 써보면, 이게 생각보다 팀 분위기 자체를 바꿉니다. 예전에는 "API 나오면 연결해볼게요"라는 말이 회의마다 반복됐는데, Mock을 도입한 이후에는 프론트엔드 쪽에서 UI 흐름을 먼저 만들어놓고, 백엔드가 완성되는 시점에 실제 API로 교체하는 방식으로 굴러가기 시작했습니다. 전체 개발 타임라인이 실제로 줄어드는 게 느껴졌습니다.

특히 MSW(Mock Service Worker)처럼 브라우저 레벨에서 네트워크 요청을 가로채는 도구를 쓰면, 코드 구조를 거의 바꾸지 않고도 Mock과 실제 API를 전환할 수 있습니다. MSW는 서비스 워커를 통해 HTTP 요청을 인터셉트하는 방식으로 동작해서, 실제 fetch나 axios 코드를 그대로 유지한 채로 Mock 환경을 구성할 수 있다는 점이 실무에서 꽤 편리합니다. 단위 테스트(Unit Test, 개별 기능을 독립적으로 검증하는 테스트)에서도 외부 의존성을 제거할 수 있어서 CI/CD 파이프라인에서 안정적인 자동화 테스트를 돌리는 데도 도움이 됩니다.

일반적으로 병렬 개발의 효과를 단순히 "속도가 빨라진다"는 식으로 설명하는 경우가 많은데, 제 경험상 이건 좀 다릅니다. 속도보다 중요한 건 각 팀이 서로의 진행 상황에 덜 의존하게 된다는 점, 즉 불필요한 커뮤니케이션 비용이 줄어든다는 게 더 큰 실익이었습니다.

검증 한계: Mock이 진짜가 아니라는 사실을 잊으면 안된다

Mock 환경에서 완벽하게 돌아가던 기능이 실제 API와 연결하는 순간 오류를 뿜는 경험, 한 번쯤은 해봤을 겁니다. 저도 그랬습니다. 그때 처음으로 "Mock은 결국 시나리오를 직접 짜는 사람의 상상력에 의존한다"는 걸 실감했습니다.

Mock API는 미리 정의한 데이터만 반환하기 때문에, 실제 서버에서 발생하는 예외 상황을 전부 커버하기가 어렵습니다. 예를 들어 응답 지연(Latency), 서버에서 내려오는 미세한 데이터 타입 차이, 혹은 인증 토큰 만료 시 처리 방식 같은 것들은 Mock에서 의도적으로 시나리오를 짜지 않으면 그냥 통과됩니다. 그리고 통합 테스트(Integration Test, 여러 컴포넌트나 시스템이 연결된 상태에서 전체 흐름을 검증하는 테스트) 단계에서 이게 한꺼번에 터지면 수정 비용이 예상보다 훨씬 커집니다.

제 경험상 가장 흔하게 걸리는 지점은 다음 세 가지였습니다.

  1. Mock 데이터의 null 처리: 실제 API는 특정 조건에서 필드를 아예 내려주지 않는 경우가 있는데, Mock에서는 항상 값이 있다고 가정하고 개발하게 됩니다.
  2. 에러 코드 해석 차이: HTTP 상태 코드는 같아도 실제 서버의 에러 메시지 구조가 Mock과 미묘하게 다른 경우가 있습니다.
  3. Mock과 실제 API의 스키마 불일치: API 스펙이 개발 중 변경됐는데 Mock이 업데이트되지 않아 테스트가 계속 통과되는 상황.

세 번째가 특히 무서운 이유는, 테스트가 통과되고 있으니 문제가 없다고 착각하게 만들기 때문입니다. Mock과 실제 API 간의 스키마 동기화는 그냥 "해야 한다"는 원칙이 아니라, 안 하면 실제로 장애로 이어질 수 있는 실무 리스크입니다.

실무 적용: Mock을 제대로 쓰기 위한 현실적인 전략

Mock을 쓸 때 가장 중요한 원칙은 "Mock은 보조 도구지 검증 수단이 아니다"라는 인식입니다. 이 기준이 흐릿해지면 팀 전체가 가짜 안정감에 빠집니다. 그럼 실무에서 어떻게 쓰는 게 효과적인지, 제가 직접 적용해보면서 효과를 봤던 방법들을 정리해 보겠습니다.

API Contract Testing(계약 테스트, 프론트엔드와 백엔드가 합의한 API 스펙을 기준으로 양쪽 모두가 그 계약을 지키는지 검증하는 방식)을 병행하면 Mock 불일치 문제를 상당 부분 예방할 수 있습니다. Pact 같은 도구를 쓰면 Consumer(클라이언트)와 Provider(서버) 간의 스펙 계약을 코드로 관리하고, 변경이 생겼을 때 자동으로 감지할 수 있습니다. 출처: Martin Fowler - Practical Test Pyramid에서도 Mock과 계약 테스트를 레이어별로 구분해서 사용하는 전략을 권장하고 있습니다.

Mock을 어느 단계까지 쓸지 범위를 명확히 정하는 것도 중요합니다. 개발 초기 단계와 단위 테스트에서는 Mock이 효과적이지만, 스테이징(Staging, 실제 운영 환경과 동일하게 구성된 검증 환경) 단계에서는 반드시 실제 API와 연동된 테스트를 돌려야 합니다. 이 둘을 명확히 분리하지 않으면 "Mock에서 됐으니까 배포해도 되겠지"라는 판단이 나오게 됩니다.

OpenAPI Specification(OAS, API 구조를 표준화된 형식으로 문서화하는 방식)을 기반으로 Mock을 자동 생성하는 방법도 실무에서 꽤 효과적이었습니다. Swagger나 Stoplight 같은 도구를 활용하면 API 스펙 문서를 기준으로 Mock 서버를 자동으로 만들 수 있어서, 스펙이 바뀌면 Mock도 자동으로 업데이트되는 구조를 만들 수 있습니다. Mock 관리 공수를 줄이면서도 실제 API와의 싱크를 유지하는 데 이 방식이 제일 실용적이었습니다.

API Mocking은 잘 쓰면 팀 전체의 개발 속도를 실질적으로 높여주는 도구지만, 그 한계를 인식하지 않으면 오히려 통합 단계에서 더 큰 비용을 치르게 됩니다. 저는 Mock을 "개발을 빠르게 돌리기 위한 발판"으로 쓰되, "이게 진짜 검증이다"라고 착각하지 않는 것이 핵심이라고 생각합니다. Mock과 실제 API 테스트를 적절히 병행하는 구조를 팀 안에 잡아두는 것, 그게 결국 장애 없이 배포까지 가는 현실적인 경로입니다.

--- 참고---
- Martin Fowler - Practical Test Pyramid: https://martinfowler.com/articles/practical-test-pyramid.html

관련 글

댓글

이 블로그의 인기 게시물

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

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

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