Redis 캐시로 공지 조회 시간을 줄인 경험

요청이 Redis 캐시를 먼저 확인하고 캐시 미스 때만 데이터베이스를 조회하는 흐름

공지 게시물은 글이 자주 바뀌지 않지만 접속자는 반복해서 읽는다. 전월 인기 게시물도 마찬가지였다. PopcornTalk 프로젝트에서 이 조회를 매번 DB에 보내는 대신 Redis를 확인하도록 바꿨다. 캐시를 선택한 이유는 특별한 기능이 필요해서가 아니라, 같은 결과를 여러 번 계산하고 읽는 일이 실제 병목으로 보였기 때문이다.

당시 부하 테스트 기록에는 “100명의 사용자가 1초에 10번 요청”한다고 적혀 있다. 그 조건에서 공지 조회 응답 시간은 716ms에서 59ms로 줄었다. Grafana에서 기록한 시스템 CPU 최댓값은 0.291에서 0.236으로 내려갔고, 원문은 이를 19.1% 감소라고 표현했다. 두 반올림된 CPU 숫자만으로 다시 계산하면 약 18.9%이므로, 글에는 원문 표기와 원시 값 모두 남겨 둔다. 캐시 적용 뒤에는 첫 조회 이후 반복 요청에서 DB 조회가 한 번으로 줄었다는 설명도 있었다.

숫자는 인상적이지만, 지금 다시 보면 테스트 기록에 빠진 정보도 있다. 부하 도구 이름, “100명”과 “초당 10회”가 전체 부하를 뜻하는지 사용자별 부하를 뜻하는지, 응답 시간의 평균·최댓값·백분위 중 무엇인지가 명확하지 않다. 테스트 데이터 크기와 캐시 예열 상태도 남아 있지 않다. 그래서 이 결과는 해당 프로젝트에서 관찰한 값이지, Redis를 붙이면 누구나 같은 배수를 얻는다는 보장은 아니다.

Cache-Aside 적용 후 달라진 요청 흐름

적용한 구조는 Cache-Aside 방식으로 설명할 수 있다. 애플리케이션은 먼저 Redis에서 값을 찾고, 없을 때만 DB를 조회한다. 조회 결과를 TTL과 함께 Redis에 저장해 다음 요청부터 재사용한다.

공지 요청
  └─ Redis hit  → 캐시 값 반환
  └─ Redis miss → DB 조회 → Redis에 저장 → 응답

공지 수정
  └─ DB 저장 → 기존 캐시 삭제

공지처럼 읽기가 많고 수정이 드문 데이터는 이 구조와 잘 맞는다. 반대로 자주 바뀌는 재고나 사용자별 민감 데이터는 캐시의 오래된 값이 잘못된 결과를 만들 수 있다. “빠른가”와 함께 “얼마나 오래된 값을 허용할 수 있나”를 결정해야 한다.

TTL은 캐시에 남은 값의 최대 수명을 제한한다. 수정 시 관련 키를 즉시 삭제하면 다음 조회에서 DB 값을 다시 채울 수 있다. 다만 DB 갱신 직후 캐시 삭제가 실패하면 잠시 예전 공지가 보일 수 있다. 공개 페이지의 공지라면 짧은 TTL로 허용할 수도 있지만, 금액이나 재고처럼 정확성이 중요한 값은 같은 기준으로 취급하면 안 된다.

캐시 만료가 다시 병목이 되는 순간

인기 키의 TTL이 같은 시각에 끝나면 요청이 한꺼번에 DB로 몰릴 수 있다. 모두가 캐시 미스를 만나 동시에 같은 데이터를 읽기 때문이다. 이를 cache stampede라고 부르며, 캐시를 넣었는데 만료 순간 DB 부하가 더 커지는 상황을 만들 수 있다. 실제로 이런 문제가 관찰될 때만 단일 조회자 제어, TTL에 작은 변동 주기 추가, 조기 갱신 등을 선택하면 된다. 작은 사이트에 처음부터 복잡한 갱신 시스템을 붙일 필요는 없다.

캐시 저장 비용도 있다. 객체 직렬화, 네트워크 왕복, Redis 메모리, 키 만료와 무효화 코드를 유지해야 한다. 조회가 한 번뿐이거나 결과가 매우 빨리 계산되는 데이터라면 캐시를 추가해도 이득이 작을 수 있다. 캐시 hit ratio와 DB 쿼리 수를 함께 봐야 “빨라진 이유”를 설명할 수 있다.

다음 성능 테스트에 남길 기록

캐시 전후의 응답 시간을 비교할 때는 평균 하나만 적지 않겠다. 동일한 데이터셋과 서버 조건에서 캐시가 비어 있는 첫 요청, 예열 후의 반복 요청을 분리하고 p50·p95 지연 시간, 오류율, DB 쿼리 수, 캐시 적중률을 같이 남기겠다. “100명의 사용자가 초당 10회” 같은 문장도 전체 초당 요청 수인지 사용자별 요청 수인지 분명하게 적겠다.

당시 기록 다시 해석할 때 남은 질문
공지 조회 시간 716ms → 59ms 어떤 지연 시간 통계였는지 알 수 없음
시스템 CPU 최댓값 0.291 → 0.236 수집 단위와 관측 구간이 원문에 없음
CPU 감소율 원문 표기 19.1% 반올림 수치 기준 재계산은 약 18.9%
부하 조건 100명, 초당 10회 요청 부하 분배 방식과 도구 정보가 부족함

기록을 다시 쓰면서 수치의 한계까지 공개하는 이유는 결과를 깎아내리기 위해서가 아니다. 다음 성능 개선에서 비교 가능한 기준을 남기기 위해서다. 캐시는 Redis를 추가하는 작업이 아니라, 어떤 데이터를 얼마나 오래 재사용하고 언제 버릴지 정하는 설계다.

DB에서 먼저 느린 조회를 줄이는 인덱스 실험은 게시글 created_at 인덱스 적용 기록에서 이어 볼 수 있다.

참고 문서: Redis Cache-Aside

당시 기록: Redis 캐싱 적용 및 성능 측정