API 응답 속도를 빠르게 만드는 방법

2025. 12. 3. 17:32·Backend

서비스를 운영하다 보면 가장 자주 듣는 말 중 하나가 바로 “API 속도 좀 개선해 주세요.” 다. 사용자가 느린 응답을 경험하면 서비스 만족도는 즉시 떨어지고, 심하면 이탈까지 이어진다. 그렇다면 서버 개발자는 API 응답 속도를 어떻게 개선할 수 있을까?

방법은 다양하지만 많은 프로젝트에서 가장 효과가 높고 적용 난도가 적당한 것이 바로 캐싱(Caching) 과 페이징(Pagination) 처리다.

이 글에서는 실제로 제가 여러 프로젝트를 진행하면서 경험한 내용을 중심으로 왜 이 두 가지가 중요한지, 어떻게 적용하는지, 각각의 장단점은 무엇인지 정리해본다.


API 성능은 왜 느려질까?

API가 느려지는 원인은 크게 세 가지다.

1) DB 조회 부하

  • 복잡한 조인
  • 대량 데이터 Full Scan
  • 인덱스 미사용
  • 명령어 자체의 비용(ORDER BY, GROUP BY 등)

2) 네트워크/시스템 부하

  • 많은 사용자 동시 접속
  • 외부 API 호출 지연
  • 과도한 직렬화/역직렬화(Json 파싱 등)

3) 비효율적인 API 설계

  • 필요한 것보다 많은 데이터를 조회
  • N+1문제
  • 페이징 없음
  • 캐싱 없음

이 중 실무에서 가장 빠르게 개선할 수 있는 부분이 바로 “캐싱”과 “페이징 처리”다.


캐싱(Caching)으로 API 속도를 높이는 방법

캐싱이란?

한 번 계산하거나 조회한 결과를 메모리나 외부 저장소에 저장해두고 재사용하는 것이다.

예시

“한 번 검색한 인기 게시판 목록은 5분 동안 다시 DB에서 조회하지 않는다.”

즉, DB를 100번 읽는 대신 캐시에서 99번 읽게 만드는 기술이다.


캐싱 적용 시 어떤 데이터가 효과가 좋은가?

캐싱은 모든 API에 적용하면 오히려 역효과가 난다. 실제로 효과가 좋은 유형을 골라야 한다.

1) 변화가 적은 데이터(정적 데이터)

  • 공통 코드 테이블
  • 카테고리 목록
  • 지역 목록
  • 공지사항 Top N

2) 조회량이 많고, 결과가 일정한 API

  • 인기 게시글
  • 메인 페이지 구성 데이터
  • 추천 상품 목록

3) 정렬·필터링 정책이 고정된 리스트


캐싱 방법들

Spring Cache (로컬 캐싱)

예시

Caffeine / ConcurrentHashMap 기반

@Cacheable(cacheNames = "hotPosts", key = "'top10'")
public List<Post> getHotPosts() {
    return postRepository.findTop10ByOrderByViewCountDesc();
}

장점

  • 적용 쉬움(애노테이션 한 줄)
  • 응답 속도 매우 빠름
  • API 서버의 메모리를 활용하므로 외부 의존 적음

단점

  • 서버가 여러 대일 경우 캐시 불일치 발생
  • 메모리 사용량 증가

Redis 캐싱(분산 캐시)

대부분의 실무 서비스에서 가장 많이 쓰는 방식.

예시

String key = "post:" + postId;
String cached = redis.get(key);

if (cached != null) return cached;

// 없으면 DB에서 조회 후 Redis에 저장

장점

  • 모든 서버 간 캐시 공유 가능
  • 높은 처리량
  • TTL을 활용한 안정적 만료 처리 가능

단점

  • Redis 장애 시 성능 급락
  • 설정 및 운영 비용 증가
  • 네트워크 Hop이 추가되어 로컬 캐싱보다는 느림

Reverse Proxy 캐싱(Nginx, CloudFront 등)

API 서버 앞단에서 캐싱하는 방식.

장점

  • API 서버로 트래픽 자체가 감소
  • CDN을 쓰면 글로벌 캐싱 가능

단점

  • 적용 범위 제한(주로 GET 요청)
  • 캐시 무효화(Invalidation) 전략 필요

캐싱 시 주의해야 할 문제들

1) 캐시 불일치(Cache Inconsistency)

데이터는 변경되었는데 캐시는 그대로 남아 있는 상황.

해결

  • TTL(TIme to Live) 설정
  • 변경 시 캐시 삭제(Cache Evict)

2) 캐시 중복 갱신(Stampede)

동시에 여러 요청이 캐시를 갱신하려고 DB를 때림.

해결

  • Redis 분산 락
  • Cache-aside 패턴
  • Lazy caching + single flight 방식

3) 캐시 메모리 부족

TTL이 짧으면 의미가 없고 길면 메모리가 부족해짐.

해결

  • LRU, LFU 등 캐시 정책 적용
  • 캐시 대상 선정 철저히

페이징(Pagination)으로 API 속도 개선하기

왜 페이징이 중요한가?

많은 초급 개발자들이 놓치는 부분이 하나 있다.

“대량 데이터 조회는 캐싱보다 페이징이 먼저다.”

예를 들어 게시판 글이 100만 건이라면 100만 건을 API로 다 내려줄 리는 없다. 페이징을 안 하면 그 순간부터 서비스는 느려진다.

  • DB의 Full Scan
  • 네트워크 전송량 증가
  • Jackson 직렬화 부하

그래서 대부분의 실무에서는 페이징이 사실상 필수 기능이다.


페이지네이션 Type별 설명

Offset 기반 페이징 (일반적인 페이징)

SQL의 LIMIT, OFFSET 사용.

예시

SELECT * 
FROM posts 
ORDER BY id DESC
LIMIT 20 OFFSET 40;

장점

  • 개발이 쉬움
  • 대부분의 RDB에서 표준 지원

단점

  • 페이지 번호가 커질수록 느려짐 (OFFSET 비용 증가)
  • 대규모 테이블에서 비효율적

Cursor 기반 페이징 (Keyset Pagination)

특정 기준 값 이후 데이터를 가져오는 방식.

예시

SELECT * 
FROM posts 
WHERE id < :cursor 
ORDER BY id DESC 
LIMIT 20;

장점

  • 대규모 데이터에서도 매우 빠름
  • 인덱스만 타면 성능 최상

단점

  • 페이지 점프가 어려움
  • 구현 난이도가 조금 있음

캐싱 + 페이징 조합 전략

실무에서는 자주 아래처럼 조합한다.

상황 추천 전략
메인 화면의 인기 게시글 캐싱(Caffeine/Redis)
통계 조회처럼 변경이 거의 없는 데이터 장기 캐싱
게시판 목록처럼 데이터 양이 많음 페이징 필수
검색 결과처럼 매번 달라지는 데이터 캐싱 비효율, 페이징 사용
트래픽이 많은 인기 API 페이징 + 일부 구간 캐싱 조합

예시

  • 인기 게시글 Top 100 → 캐싱
  • 게시판 전체 글 목록 → 페이징(Offset or Cursor)
  • 게시판 내 인기 글 모음 → 캐싱 + 페이징 혼합

실무 시나리오 예시

제가 개인 프로젝트에서 겪었던 문제 중 하나는

“메인 페이지에 인기 게시글 8개를 노출하는 API가 너무 느리다.”

DB 정렬 + 집계 쿼리가 무거웠기 때문이다.

해결 방법

  1. 해당 결과를 캐싱(5분 TTL)
  2. 게시판 전체 글 목록은 Offset → Cursor 페이징으로 변경

결과

  • 200ms → 20ms로 응답 속도 10배 개선
  • DB 부하 60% 감소

지금은 대부분의 서비스에서 “조회량 많은 데이터는 캐시, 대량 리스트는 페이징”

이 조합을 기본 전략으로 잡고 있다.


마무리

API 응답 속도를 빠르게 만들기 위해 무조건 서버 스펙을 늘리거나 DB 튜닝을 하는 것이 답은 아니다.
많은 경우 단순히 캐싱과 페이징만 잘 적용해도 성능이 극적으로 향상된다.

정리하자면

  • 캐싱은 변경이 적고 조회가 많은 데이터에 강력
  • 페이징은 대량 데이터 조회에서 필수
  • 캐싱 + 페이징 조합은 대부분의 서비스에서 사실상 표준 구성

특히 REST API 기반의 서비스라면 캐싱과 페이징을 통해 체감 성능을 크게 올릴 수 있다.

저작자표시 (새창열림)
'Backend' 카테고리의 다른 글
  • @Transactional 동작 원리
  • 폐쇄망 환경에서 서로 다른 두 DB를 다뤄야 할 때
  • 온프레미스 환경에서 무중단 배포(Zero Downtime Deployment) 구축 방안 탐구기
  • REST API
쭈니어 개발자
쭈니어 개발자
    홈 |
  • 쭈니어 개발자
    주니어 개발자 공부 기록
    쭈니어 개발자
  • 글쓰기 관리
  • 전체
    오늘
    어제
  • GitHub

    Notion

    • 분류 전체보기 (134)
      • Frontend (4)
      • Backend (21)
      • Database (4)
      • Data Structure & Algorithm (41)
      • Network (16)
      • IT Education (48)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 태그

    트리의 지름
    자바
    백준
    코테
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.4
쭈니어 개발자
API 응답 속도를 빠르게 만드는 방법
상단으로

티스토리툴바