Redis를 사용하여 백엔드 쿼리 최적화

발행: (2026년 2월 4일 오후 03:12 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

원래 접근 방식 (편안한 방법)

엔드포인트 로직은 간단했습니다:

  1. 데이터베이스 조회
  2. 점수 순으로 사용자 정렬
  3. 상위 10명 반환
SELECT * FROM users ORDER BY score DESC LIMIT 10;

적절한 인덱싱을 하면 소규모에서는 잘 동작했지만, 리더보드는:

  • 자주 접근됨
  • 자주 업데이트됨
  • 경쟁이 치열한 실시간 데이터

매 요청마다 데이터베이스에 접근하는 것은 곧 문제로 떠올랐습니다.

첫 번째 시도: Redis 사용하기

Redis는 메모리 기반, 빠르고 순위 매기기에 최적화돼 있어 완벽해 보였습니다.
하지만 로컬에서 실행하니 오류가 발생했습니다:

Error: Address already in use
Port 6379 was already occupied.

서비스를 재시작하고 프로세스를 종료해 보았지만 해결되지 않아, Redis를 제대로 격리하기로 했습니다.

해결책: Redis 도커화

docker run -d -p 6379:6379 --name redis-server redis

컨테이너에서 Redis를 실행하면:

  • 격리됨
  • 이식 가능함
  • 깔끔하게 실행됨
  • 재시작이 쉬움

환경이 정리되니 작업을 진행할 수 있었습니다.

정렬된 집합 (ZSET) 도입

Redis Sorted Sets는 자동으로 멤버를 점수 기준으로 정렬합니다.

  • 멤버 → 사용자 ID
  • 점수 → 포인트

이 덕분에 SQL 정렬과 무거운 DB 읽기가 필요 없게 되었습니다.

사용자의 점수 업데이트

await redis.zadd("leaderboard", score, userId);

상위 10명 가져오기

await redis.zrevrange("leaderboard", 0, 9, "WITHSCORES");

이제 순위 로직이 전부 메모리에서 처리되며, 지연 시간이 즉시 개선되었습니다.

예상치 못한 숨은 병목 현상

상위 10명의 사용자 ID를 가져온 뒤, 추가적인 사용자 상세 정보(이름, 아바타 등)가 필요했습니다:

for (let userId of topUsers) {
  await redis.hgetall(`user:${userId}`);
}

이로 인해 Redis 내부에서 N+1 문제가 발생했습니다:

  • 1 요청 → 리더보드 조회
  • 10 요청 → 각각의 사용자 조회

결과: 총 11번의 네트워크 왕복, 약 100 ms 추가 지연.

진짜 해결책: Redis 파이프라이닝

Redis 파이프라이닝은 명령을 배치해 왕복 횟수를 줄여줍니다.

const pipeline = redis.pipeline();
for (let userId of topUsers) {
  pipeline.hgetall(`user:${userId}`);
}
const users = await pipeline.exec();

이제 한 번의 네트워크 왕복만 필요해 N+1 지연이 사라졌습니다.

결과

단계지연 시간
DB 정렬~200 ms
Redis (파이프라인 없음)~120 ms
Redis + 파이프라인~20 ms

네트워크 호출을 줄인 덕분에 10배 정도의 개선을 이루었습니다.

배운 점

  • 인프라 문제가 최우선 – Redis가 정상적으로 실행되지 않으면 다른 건 의미가 없습니다.
  • 데이터 구조가 중요 – ZSET 덕분에 반복적인 정렬 자체가 사라졌습니다.
  • N+1 문제는 DB에만 국한되지 않음 – 원격 시스템에서도 발생할 수 있습니다.
  • 네트워크 지연은 눈에 보이지 않지만 비용이 큼 – “빠른” 시스템도 호출이 잦으면 느려집니다.
  • Docker가 백엔드 생활을 단순화 – 의존성을 컨테이너화하면 OS 수준 충돌을 피할 수 있습니다.

최종 아키텍처

  1. 점수 업데이트ZADD
  2. 상위 10명 조회ZREVRANGE
  3. 사용자 데이터 일괄 조회 → 파이프라인 + EXEC
  4. 응답 반환

데이터베이스 접근 없이, 전부 메모리에서 처리, 네트워크 호출 최소화, 응답 시간 ~20 ms.

마무리 생각

최적화는 도구를 무작정 사용하는 것이 아니라, 실제 시간이 어디에 쓰이는지 파악하는 일입니다. 이번 경우 가장 큰 성과는 다음에서 나왔습니다:

  • 환경 정비
  • 올바른 데이터 구조 선택
  • 네트워크 왕복 횟수 감소

이 세 가지를 해결한 것이 모든 차이를 만들었습니다.

Back to Blog

관련 글

더 보기 »

Redis 소개: 그것이 무엇이며 왜 빠른가

Redis란 무엇인가? Redis Remote DIctionary Server는 오픈소스이며 인메모리 데이터 구조 저장소로, 가장 인기 있는 NoSQL 데이터베이스 중 하나입니다. Salvato가 만들었습니다.