Redis는 알겠는데, 그래서 뭘 어떻게 넣으라는 거지
Redis가 빠르다는 건 나도 오래전부터 알고 있었다. 면접 단골 질문이라 “인메모리라서 빠르고 단일 스레드고…” 정도는 줄줄 외웠다. 그 원리는 지난 글에도 정리해뒀다.
문제는 정작 “이 조회가 느리니까 Redis로 캐싱하자"는 상황이 왔을 때였다. 서버를 띄우고 redis-cli를 켜긴 했는데, 그 다음이 막막했다. 뭘 어떤 키로 넣고, 무슨 명령을 쓰고, 언제 지워야 하는가. 원리를 아는 것과 실제로 붙이는 건 완전히 다른 얘기였다.
이 시리즈는 그때의 나 같은 사람을 위한 것이다. 원리는 접어두고, 설치부터 시작해서 실제 서비스에 캐시·세션·랭킹을 붙이는 데 필요한 것만 흐름대로 다룬다. 첫 편은 개념 잡기와 설치, 그리고 첫 명령어다.
먼저 사고방식부터 — Redis는 DB가 아니다
Redis를 처음 붙일 때 가장 헷갈렸던 게 이거였다. “이거 DB랑 뭐가 다르지? 그냥 빠른 DB 아닌가?” 아니다. 역할이 다르다.
Redis는 메모리에 데이터를 저장하는 Key-Value 저장소다. MySQL 같은 DB가 디스크에 데이터를 안전하게 보관하는 창고라면, Redis는 자주 쓰는 데이터를 손 닿는 곳에 잠깐 올려두는 작업대에 가깝다.
일반 DB (MySQL) Redis
───────────────── ─────────────────
디스크 저장 (영구) 메모리 저장 (빠름, 휘발성 주의)
복잡한 쿼리 / 조인 단순 Key로 값 꺼내기
ms(밀리초) 단위 μs(마이크로초) 단위 — 훨씬 빠름
데이터의 "원본" 원본의 "사본 / 임시 데이터"
여기서 딱 하나만 몸에 새기고 가면 된다. Redis에 있는 데이터는 언제 날아가도 되는 것만 넣는다. 메모리 기반이라 서버가 재시작되면 사라질 수 있다(영속성 옵션이 있긴 하지만, 그건 안전망이지 보험이 아니다). 그래서 나는 항상 “이 데이터, Redis가 통째로 비어도 DB에서 다시 만들 수 있나?“를 먼저 자문한다. 답이 “아니오"면 그건 Redis에 단독으로 둘 데이터가 아니다.
이 원칙만 지켜도 초보가 저지르는 사고의 절반은 안 난다. 이 시리즈에서 하나씩 실제로 붙여볼 용도는 이렇다.
- 캐시: 느린 DB 조회 결과를 잠깐 저장해 다음 요청을 빠르게 (#3)
- 세션 저장소: 로그인 정보를 서버 여러 대가 공유 (#4)
- 실시간 랭킹 / 카운터: 조회수, 좋아요, 게임 점수 (#4)
- 선착순 / 횟수 제한: “1분에 5번만” 같은 제어 (#4)
- 임시 데이터: 이메일 인증코드처럼 시간 지나면 알아서 사라지는 값
전부 “없어져도 DB로 복구되거나, 애초에 임시"라는 공통점이 있다. 우연이 아니다.
설치 — 고민 말고 Docker
로컬에서 굴려볼 거라면 나는 그냥 Docker로 띄운다. 버전 관리도 편하고, 다 쓰고 컨테이너만 지우면 흔적이 안 남는다.
# Redis 실행 (포트 6379)
docker run --name my-redis -p 6379:6379 -d redis:7
# 컨테이너 안의 redis-cli로 바로 접속
docker exec -it my-redis redis-cli
로컬에 직접 깔고 싶으면 이것도 어렵지 않다.
# macOS
brew install redis
redis-server # 서버 실행
redis-cli # 다른 터미널에서 접속
# Ubuntu / Debian
sudo apt install redis-server
Windows는 얘기가 좀 다르다. Redis는 공식 Windows 지원이 없어서, 예전 마이크로소프트 포트를 찾아 깔면 버전이 한참 낡았다. 삽질하지 말고 WSL2 + apt나 Docker로 가는 게 정답이다.
접속이 됐는지는 PING 한 번이면 안다.
127.0.0.1:6379> PING
PONG # 이게 뜨면 성공
첫 명령어 — 넣고, 빼고, 만료시키기
redis-cli는 Redis랑 직접 대화하는 창구다. 코드로 붙이기 전에 여기서 손으로 쳐보는 게 감을 잡는 제일 빠른 길이다.
# 값 저장 / 조회 / 삭제
SET name "kastori"
GET name # "kastori"
DEL name
# 키가 있는지 확인
EXISTS name # 1(있음) / 0(없음)
# 만료 시간(TTL) — 이게 Redis의 진짜 무기다
SET code "123456" EX 300 # 300초 뒤 알아서 사라짐 (이메일 인증코드에 딱)
TTL code # 남은 초. -1은 만료없음, -2는 이미 없는 키
# 숫자 카운터
SET views 0
INCR views # 1
INCR views # 2
INCRBY views 10 # 12
여기서 두 가지를 짚고 싶다.
첫째, EX로 거는 TTL. RDB로 임시 데이터를 다루던 사람이 Redis에 오면 제일 감동하는 부분이 이거다. 인증코드 5분 뒤 만료? DB였으면 expires_at 컬럼 만들고 배치 돌려 지웠을 일을 EX 300 한 방이면 끝낸다. 앞으로 캐시든 세션이든 TTL이 계속 나오니 지금 눈에 익혀두자.
둘째, INCR. 별것 아닌 것 같지만 이게 원자적이라는 게 핵심이다. 조회수를 GET해서 +1 하고 다시 SET하면 동시 요청에서 값이 꼬이는데, INCR은 Redis가 명령을 하나씩 처리하기 때문에 락 없이도 정확하다. 조회수·좋아요 카운터를 마음 편히 맡길 수 있다.
딱 하나만 외워라: KEYS * 금지
실무에서 Redis로 사고 치는 대표적인 방법이 KEYS *다. “키 목록 좀 보자” 하고 운영 서버에 쳤다가 Redis 전체를 멈춰버리는 경우를 심심찮게 본다. 전체 키를 한 번에 훑는 O(N) 명령인데, Redis는 단일 스레드라 그동안 다른 요청이 전부 대기한다(원리편에서 왜 그런지 자세히 다뤘다).
키를 훑어야 하면 커서로 조금씩 도는 SCAN을 쓴다.
SCAN 0 MATCH user:* COUNT 100 # 블로킹 없이 100개씩 나눠서 조회
로컬에서 KEYS는 편하니까 습관이 들기 쉬운데, 그 습관이 운영에서 사고로 이어진다. 처음부터 SCAN으로 손에 익히는 걸 권한다.
키 이름은 :으로 계층 짓기
마지막으로 사소하지만 나중에 크게 갈리는 습관 하나. 키 이름은 user:1:name처럼 :으로 계층을 준다.
user:1:name
user:1:cart
session:abc123
post:100:views
:는 Redis 입장에선 그냥 글자지만, 관례로 굳어져서 도구들도 이 기준으로 키를 트리처럼 보여준다. SCAN user:1:*로 묶어 찾기도 좋고, 무엇보다 반년 뒤에 봐도 이게 무슨 키인지 바로 읽힌다. 처음에 대충 user1name 같이 지어두면 나중에 후회한다.
마치며
여기까지면 Redis를 띄우고 값을 넣고 빼고 만료시키는 것까진 손에 붙었을 것이다. 근데 사실 여기까지는 Redis를 “빠른 문자열 저장소"로만 쓴 거다. 진짜 힘은 String 말고 나머지 자료구조를 상황에 맞게 고르는 데 있다.
다음 편에서는 Hash·List·Set·Sorted Set을 각각 어떤 실무 상황에서 꺼내 쓰는지, “이럴 땐 이거"를 시나리오로 풀어본다. 개인적으로 Sorted Set을 처음 알았을 때 “랭킹을 이렇게 쉽게 만든다고?” 했던 기억이 있는데, 그 얘기도 거기서 한다.