Redis를 '빠른 캐시'로만 보면 놓치는 것
Redis를 처음 들으면 보통 "빠른 캐시"라고 이해한다. 틀린 말은 아니다. Redis는 데이터를 메모리(RAM)에 올려 두고 읽고 쓰기 때문에 매우 빠른 응답을 낼 수 있다. 하지만 Redis를 캐시로만 보면 절반만 이해한 것이다.
Redis는 인메모리 데이터 구조 저장소(in-memory data structure store)다. 데이터를 키(key)로 저장하고, 그 키를 통해 값을 꺼낸다. 여기까지는 단순한 Key-Value 저장소처럼 보인다. 그러나 Redis의 값(value)은 단순 문자열만이 아니다. 문자열(String), 해시(Hash), 리스트(List), 집합(Set), 정렬된 집합(Sorted Set), 스트림(Stream) 같은 자료구조를 직접 다룰 수 있다.1
이 차이가 중요하다. 일반적인 캐시는 "어떤 결과를 잠시 저장했다가 다시 꺼내 쓰는 공간"에 가깝다. 반면 Redis는 "자주 쓰는 데이터를 빠르게 저장하는 공간"이면서 동시에 "실시간 기능을 만들기 위한 도구 상자"에 가깝다.
예를 들어 다음 기능들은 모두 Redis로 만들 수 있다.
상품 상세 조회 결과를 30초 동안 저장하는 캐시
로그인 사용자의 세션 저장소
실시간 인기 게시글 랭킹
1분에 100번까지만 요청을 허용하는 속도 제한기(rate limiter)
작업을 순서대로 처리하는 간단한 큐(queue)
여러 서버에 이벤트를 전달하는 메시지 브로커(message broker)
즉 Redis는 "빠른 저장소"라기보다, 짧은 지연 시간(latency)이 중요한 문제를 자료구조와 명령어로 해결하는 플랫폼에 가깝다.
AI 생성 이미지
왜 메모리 기반이면 빠를까
전통적인 관계형 데이터베이스(RDBMS)는 보통 디스크를 중심으로 설계된다. 물론 데이터베이스도 내부적으로 메모리 캐시를 적극 활용한다. 하지만 최종적으로는 디스크에 안전하게 기록하고, 테이블·인덱스·트랜잭션 로그 같은 구조를 관리해야 한다.
Redis는 접근 방식이 다르다. Redis의 기본 작업 공간은 메모리다. 클라이언트가 GET user:1 같은 명령을 보내면 Redis는 메모리에 있는 키를 찾아 값을 돌려준다. 디스크에서 페이지를 읽어 오거나 복잡한 실행 계획을 세우는 과정이 상대적으로 적다. 그래서 단순 조회와 갱신에서 매우 낮은 지연 시간을 기대할 수 있다.
물론 "메모리에 있으니 무조건 좋다"는 뜻은 아니다. 메모리는 디스크보다 비싸고 용량이 작다. 서버가 재시작되면 메모리의 데이터는 사라질 수 있다. Redis는 RDB 스냅샷과 AOF(Append Only File) 같은 영속성 기능을 제공하지만, Redis의 핵심 동작은 여전히 메모리를 중심으로 한다.2
따라서 Redis를 관계형 데이터베이스의 완전한 대체재로 생각하면 위험하다. 주문, 결제, 정산처럼 강한 일관성과 복잡한 조회가 필요한 데이터는 보통 관계형 데이터베이스가 더 적합하다. Redis는 그 옆에서 빠른 응답, 실시간 상태, 임시 데이터, 이벤트 처리를 맡을 때 빛난다.
Redis가 잘 맞는 대표 상황
Redis를 도입할지 판단할 때는 "빠른 저장소가 필요하다"보다 더 구체적으로 생각해야 한다. 문제의 모양이 Redis의 자료구조와 잘 맞을수록 효과가 크다.
캐시
가장 흔한 사용 사례는 캐시(cache)다. 예를 들어 상품 상세 페이지를 볼 때마다 데이터베이스에서 상품, 가격, 리뷰 수, 재고 정보를 조합해 가져온다고 해 보자. 트래픽이 늘면 데이터베이스 부하가 커진다.
이때 Redis에 조회 결과를 잠시 저장해 둘 수 있다.
product:detail:1001 -> 상품 상세 응답 JSON이 키에 30초나 1분의 만료 시간(TTL)을 설정하면, 같은 상품을 다시 조회할 때 데이터베이스를 거치지 않고 Redis에서 빠르게 응답할 수 있다.
캐시는 특히 다음 조건에서 효과적이다.
같은 데이터를 반복해서 읽는다.
약간 오래된 데이터를 잠시 보여줘도 괜찮다.
데이터베이스 조회 비용이 크다.
트래픽이 순간적으로 몰릴 수 있다.
반대로 매번 최신 값이 반드시 필요하거나, 데이터가 거의 재사용되지 않는다면 캐시 효과는 작다.
세션 저장소
웹 애플리케이션 서버가 여러 대로 늘어나면 세션 관리가 어려워진다. 사용자가 A 서버에서 로그인했는데 다음 요청이 B 서버로 가면, B 서버도 그 사용자의 로그인 상태를 알아야 한다.
이때 Redis를 중앙 세션 저장소로 사용할 수 있다.
session:abc123 -> { userId: 42, role: "USER" }세션은 보통 일정 시간이 지나면 만료되어야 하므로 Redis의 TTL과 잘 맞는다. 또한 모든 애플리케이션 서버가 같은 Redis를 바라보면 서버를 수평 확장하기 쉬워진다.
랭킹 시스템
게임 점수, 인기 게시글, 많이 팔린 상품처럼 순위가 필요한 기능은 Redis의 Sorted Set과 잘 맞는다. Sorted Set은 값(member)과 점수(score)를 함께 저장하고, 점수를 기준으로 정렬된 결과를 빠르게 가져올 수 있다.
예를 들어 게임 랭킹은 다음처럼 생각할 수 있다.
leaderboard:daily
- user:7 score 9800
- user:15 score 9100
- user:3 score 8700관계형 데이터베이스에서도 ORDER BY score DESC LIMIT 10으로 랭킹을 구할 수 있다. 하지만 점수가 계속 바뀌고 상위 N명을 자주 조회한다면 Redis가 더 단순하고 빠른 해법이 될 수 있다.
속도 제한기
API를 운영하다 보면 특정 사용자나 IP가 짧은 시간에 너무 많은 요청을 보내는 상황이 생긴다. 이때 Redis의 원자적 증가 명령을 사용하면 간단한 속도 제한기를 만들 수 있다.
예를 들어 rate:user:42:202605301210 같은 키를 만들고, 요청이 올 때마다 값을 1씩 증가시킨다. 1분 동안 값이 100을 넘으면 요청을 막는다. 이 키에는 1분 뒤 만료 시간을 둔다.
여기서 중요한 점은 Redis의 증가 연산이 원자적으로 처리된다는 것이다. 여러 서버가 동시에 요청을 보내도 카운터 값이 꼬이지 않게 만들 수 있다. 원자성은 뒤 장에서 더 자세히 다룬다.
메시징과 큐
Redis는 메시지를 전달하는 용도로도 쓰인다. 단순한 실시간 알림에는 Pub/Sub을 사용할 수 있고, 작업을 순서대로 처리해야 하는 경우에는 List나 Stream을 사용할 수 있다.
예를 들어 이미지 리사이징 작업을 큐에 넣고, 백그라운드 워커가 하나씩 꺼내 처리할 수 있다.
queue:image-resize -> [job1, job2, job3]다만 메시징은 요구 사항을 잘 봐야 한다. 메시지 유실을 절대 허용할 수 없고, 재처리·순서 보장·장기 보관·복잡한 라우팅이 필요하다면 전문 메시지 시스템이 더 적합할 수 있다. Redis는 가볍고 빠른 처리에 강하지만 모든 메시징 문제의 정답은 아니다.
Redis를 도입하면 좋아지는 경우
Redis는 다음 상황에서 특히 효과적이다.
첫째, 반복 조회가 많고 응답 시간이 중요한 경우다. 인기 상품, 메인 화면 데이터, 사용자 프로필처럼 자주 읽히는 데이터를 캐싱하면 데이터베이스 부하를 크게 줄일 수 있다.
둘째, 데이터가 짧은 생명주기를 가진 경우다. 세션, 인증 코드, 임시 토큰, 속도 제한 카운터처럼 시간이 지나면 사라져야 하는 데이터는 TTL과 잘 맞는다.
셋째, 자료구조가 문제와 잘 맞는 경우다. 랭킹은 Sorted Set, 큐는 List나 Stream, 중복 제거는 Set, 객체 일부 필드 갱신은 Hash로 표현할 수 있다. 문제를 Redis 자료구조로 자연스럽게 표현할 수 있다면 구현이 단순해진다.
넷째, 여러 애플리케이션 서버가 공유해야 하는 빠른 상태가 필요한 경우다. 로컬 메모리에 저장하면 서버마다 값이 달라질 수 있다. Redis를 중앙에 두면 여러 서버가 같은 상태를 공유할 수 있다.
Redis가 오히려 복잡도를 늘리는 경우
Redis를 추가하면 시스템 구성 요소가 하나 늘어난다. 장애 지점도 늘고, 운영해야 할 대상도 늘어난다. 따라서 효과가 불분명한데 "빠르다니까" 도입하면 오히려 복잡해진다.
다음 상황에서는 신중해야 한다.
첫째, 데이터가 너무 크고 대부분을 메모리에 올려야 하는 경우다. Redis는 메모리 기반이므로 대용량 장기 저장소로 쓰면 비용이 커질 수 있다.
둘째, 복잡한 검색과 조인이 핵심인 경우다. 관계형 데이터베이스는 테이블 간 조인, 조건 검색, 집계, 트랜잭션에 강하다. Redis에 같은 역할을 억지로 맡기면 애플리케이션 코드가 복잡해진다.
셋째, 강한 영속성과 정합성이 최우선인 경우다. Redis도 영속성 옵션을 제공하지만, 기본 철학은 메모리 기반의 빠른 처리다. 절대 잃으면 안 되는 원장성 데이터는 주 데이터베이스에 저장하고 Redis는 보조 역할로 두는 편이 안전하다.
넷째, 캐시 무효화 전략이 없는 경우다. 캐시는 저장하는 것보다 지우는 것이 더 어렵다. 원본 데이터가 바뀌었는데 Redis의 값이 그대로 남아 있으면 사용자는 오래된 정보를 보게 된다. Redis를 도입할 때는 "언제 저장할까?"뿐 아니라 "언제 지울까?"를 반드시 정해야 한다.
Key-Value에서 데이터 플랫폼으로
Redis의 출발점은 단순하다.
키로 저장하고, 키로 꺼낸다.하지만 실제 활용은 여기서 확장된다. 키는 데이터를 찾는 이름이고, 값은 문제에 맞는 자료구조가 된다.
String: 단순 값, JSON 문자열, 카운터Hash: 사용자 프로필 같은 객체List: 순서가 있는 작업 목록Set: 중복 없는 사용자 목록Sorted Set: 점수 기반 랭킹Stream: 이벤트 로그와 소비자 그룹
이 자료구조들은 단순히 데이터를 담는 그릇이 아니다. 각 자료구조에는 그에 맞는 명령어가 있다. 숫자를 증가시키고, 목록의 한쪽 끝에 값을 넣고, 집합의 교집합을 구하고, 점수 범위로 랭킹을 조회할 수 있다.
그래서 Redis를 배운다는 것은 명령어를 외우는 일이 아니다. "이 문제는 어떤 자료구조로 표현할 수 있을까?"를 익히는 일이다.
이 책에서 Redis를 바라보는 관점
이 책은 Redis를 관계형 데이터베이스의 경쟁자로 다루지 않는다. Redis는 많은 경우 주 데이터베이스 옆에서 동작한다. 데이터베이스가 영속성과 복잡한 조회를 맡고, Redis가 빠른 응답과 실시간 상태를 맡는다.
앞으로 우리는 다음 흐름으로 Redis를 배운다.
먼저 개발 환경을 준비하고 가장 기본적인 명령어를 실행한다. 그다음 키 설계와 만료 시간을 다루며 Redis 데이터의 생명주기를 이해한다. 이후 문자열, Hash, List, Set, Sorted Set 같은 자료구조를 실제 서비스 기능과 연결한다. 후반부에서는 캐시 전략, 메시징, 영속성, 복제, 클러스터, 성능 튜닝, 운영 체크리스트까지 이어 간다.
첫 장에서 기억할 핵심은 하나다.
Redis는 단순히 빠른 캐시가 아니다. 메모리 기반의 빠른 처리와 다양한 자료구조를 이용해 실시간 애플리케이션 문제를 해결하는 데이터 플랫폼이다.
참고
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.