Redis 핵심 정리 시리즈 첫 글. Redis가 왜 그렇게 빠른지부터 책상 위 메모리 사물함 비유로 풀어가며 — 인메모리 DB 구조, RAM과 디스크 속도 차이, 데이터 타입 7종 개요, 키 네이밍 베스트 프랙티스, redis-cli 기본 사용, 클라이언트 라이브러리(node-redis·Jedis·Lettuce·redis-py)의 정체, 운영에서 절대 피해야 할 KEYS *까지 처음 보는 사람도 따라올 수 있게 친절하게 풀어쓴 1편.
이 글은 Redis 핵심 정리 시리즈의 첫 번째 편입니다. 백엔드 개발을 어느 정도 하다 보면 자연스럽게 Redis 이야기가 나와요. "캐시는 Redis로", "세션은 Redis에", "리더보드는 Redis Sorted Set으로" — 이렇게 자주 등장하는 만큼, 한 번 단단히 잡아두면 두고두고 쓸 수 있는 도구입니다.
이 시리즈는 9편을 통해 Redis의 큰 그림과 실전 패턴을 차근차근 쌓아 갑니다. 한 번에 다 외우려 하지 마시고, 이번 1편에서는 "Redis가 왜 그렇게 빠른가, 어떤 데이터 모델인가, 어떻게 시작하나" — 이 세 가지 질문의 답만 머리에 들어와도 충분합니다.
본문 흐름은 책상 위 메모리 사물함 비유를 따라 풀어 가요. 디스크 창고에 가지 않고 책상 위 메모리에 바로 자료를 두면 — 그게 Redis의 정체입니다.
이 시리즈는 Redis 공식 문서, redis.io 명령어 레퍼런스, 여러 인메모리 DB 학습 자료 등 공개 자료를 참고해 한국어 학습 노트로 풀어쓴 자료입니다.
로컬에 Redis를 한 번 띄우고 redis-cli로 명령을 직접 쳐 보면 본문이 머리에 훨씬 잘 박혀요. brew install redis(macOS) 또는 docker run -p 6379:6379 redis로 1분이면 시작됩니다.
왜 Redis가 처음엔 어렵게 느껴질까요
이유는 네 가지예요.
첫째, "왜 RAM에 저장하냐"가 직관적으로 안 옵니다. 데이터베이스라는 단어를 들으면 보통 디스크에 저장하는 걸 떠올리는데, Redis는 그 반대예요. "RAM에 두면 서버 꺼지면 다 날아가는 거 아니야?" 같은 의문이 자연스럽게 들죠.
둘째, SQL DB와 비슷한 듯 다른 듯 모호해요. 데이터를 저장하고 가져온다는 점은 같은데, JOIN이 없고 스키마도 없고 트랜잭션도 약해요. "그럼 진짜 DB인가?" 싶어집니다.
셋째, 데이터 타입이 7종이나 됩니다. String·Hash·List·Set·Sorted Set·HyperLogLog·Stream — 한 페이지에 줄지어 나오면 머리가 어지러워요.
넷째, 클라이언트 라이브러리·명령어·ORM 관계가 헷갈려요. Java의 Jedis·Lettuce, Node의 node-redis, 파이썬의 redis-py — 다들 비슷하면서 다른데 이게 뭔지 한 번에 안 잡힙니다.
해결법은 한 가지예요. Redis를 "책상 위 메모리 사물함" 으로 잡고, 키-값을 "이름표 적힌 봉투" 로 풀면 갑자기 명확해집니다. 디스크 창고에 멀리 갔다 오는 게 아니라 책상 옆 사물함에서 바로 봉투를 꺼내는 식이에요. 이 글은 그 비유를 따라 처음부터 풀어 갑니다.
Redis가 도대체 어떤 시스템인가요
Redis — Remote Dictionary Server의 약자 — 는 모든 데이터를 컴퓨터의 RAM에 저장하는 인메모리 데이터베이스입니다. 디스크 I/O 지연을 원천적으로 제거해 데이터 접근 속도를 극대화하는 게 핵심 철학이에요.
회사 비유로 풀면 — 일반 DB는 자료 창고예요. 자료를 찾으려면 창고까지 가서 찾아야 합니다(디스크 I/O). Redis는 책상 옆 메모리 사물함이에요. 자주 보는 자료를 사물함에 넣어 두면 의자에서 손만 뻗어 꺼낼 수 있습니다.
규모를 보면 위치가 와닿아요.
- 사용자 계정·세션·캐시·리더보드·메시지 큐 등 거의 모든 백엔드의 빠른 데이터 자리에 표준
- GitHub·Twitter·Stack Overflow·Snapchat 같은 대형 서비스가 핵심 인프라로 사용
- 오픈소스 + 상용 양쪽으로 활발하게 운영
핵심 특징을 한 줄로 정리하면 — "빠르고 단순한 키-값 저장소" 입니다. 더 깊은 동작 원리는 Redis 공식 문서에서 확인할 수 있어요.
Redis가 빠른 이유 3가지
이게 입문에서 가장 헷갈리는 부분이에요. 차근차근 풀어 갑니다.
1. 인메모리 저장 — 디스크 안 거치는 차이
하드 디스크의 임의 접근(random access)은 수 밀리초(ms) 단위지만, RAM 접근은 수십 나노초(ns) 단위예요. 차이가 어마어마합니다.
디스크 접근 속도: ~10ms
RAM 접근 속도: ~100ns
차이: 약 100,000배
회사 비유로 — 창고에 가서 자료 찾는 데 10초 걸리는 일이 책상 옆 사물함에서는 0.0001초로 끝나는 식이에요. MySQL·PostgreSQL 같은 디스크 기반 DB가 따라올 수 없는 영역입니다.
2. 단순한 자료 구조
Redis는 연결 리스트·해시 맵·정렬 집합 같은 단순하고 예측 가능한 자료 구조를 그대로 노출해요. 개발자가 데이터가 메모리에서 어떻게 처리되는지 직관적으로 예측할 수 있습니다.
PostgreSQL·MySQL이 복잡한 인덱싱·조인·트랜잭션·옵티마이저 같은 기능을 제공하면서 그만큼 복잡성을 떠안는 것과 정반대 철학이에요.
3. 의도적 기능 미니멀리즘
Redis는 의도적으로 기능을 제한합니다. 복잡한 SQL JOIN, 다중 테이블 트랜잭션, 스키마 관리 — 이런 것들이 없어요. 대신 단일 데이터 구조 안에서의 빠른 읽기·쓰기에 집중합니다.
여기서 시험 함정이 하나 있어요. 이 미니멀리즘은 단점이 아니라 의도된 설계 철학입니다. "Redis가 왜 SQL JOIN을 안 지원해요?"는 "Redis는 SQL DB가 아니다"가 정답이에요. 처음 접근할 때는 이 차이를 받아들이는 게 가장 중요합니다.
> 한 줄 정리 — Redis = RAM + 단순 자료구조 + 의도적 미니멀리즘 셋의 조합. 100,000배 빠른 비결.
Redis의 한계 — 만능이 아닙니다
Redis가 빠른 만큼 한계도 분명해요. 이 부분을 명확히 알고 있어야 적재적소에 쓸 수 있습니다.
메모리 크기 제한
모든 데이터를 RAM에 저장하니까 컴퓨터 메모리 크기가 곧 데이터 크기 한계예요.
RAM 8GB 서버 → 최대 데이터 용량 ~8GB
디스크 4TB 서버 → 최대 데이터 용량 ~4TB
수백 GB 단위 분석 데이터를 통째로 Redis에 넣는 건 비현실적입니다. 그건 PostgreSQL·BigQuery 자리예요.
제한된 쿼리 기능
복잡한 JOIN, 집계 함수, 다중 테이블 검색은 기본적으로 못 합니다. 필요하면 RediSearch 모듈을 추가하거나 보조 데이터 구조를 직접 만들어 관리해야 해요.
데이터 영속성
기본은 인메모리라 서버 재시작 시 데이터 손실 가능성이 있어요. 이걸 해결하려면 RDB 스냅샷·AOF(Append Only File) 같은 영속성 메커니즘을 따로 설정해야 합니다. 자세한 영속성 전략은 4편에서 풀어 갈게요.
Redis 설치 및 시작
가장 빠른 시작 방법 두 가지를 정리합니다.
macOS — Homebrew
# 설치
brew install redis
# 백그라운드 서비스로 실행
brew services start redis
# 동작 확인
redis-cli ping
# 응답: PONG
Docker — 가장 쉬운 시작
# Redis 서버 컨테이너 실행
docker run --name my-redis -p 6379:6379 -d redis
# 컨테이너 안의 redis-cli로 접속
docker exec -it my-redis redis-cli
Ubuntu/Debian
sudo apt update
sudo apt install redis-server
sudo systemctl start redis
여기서 시험 함정이 하나 있어요. Redis 기본 포트는 6379입니다. 이 숫자는 자주 시험·면접에 등장하니 외워두면 좋아요. (참고로 6379는 알파벳 키패드의 'MERZ'를 따른 거예요 — 이탈리아 가수 Alessia Merz의 이름).
redis-cli — 명령어 한 번 손에 익혀 두기
Redis와 직접 대화하는 가장 흔한 도구가 redis-cli입니다. 한 번 손에 익혀 두면 운영·디버깅 모두 빠르게 됩니다.
연결
# 로컬 Redis 연결
redis-cli
# 원격 Redis 연결
redis-cli -h <host> -p <port> -a <password>
# 연결 테스트
redis-cli ping
# PONG
# 서버 정보 확인
redis-cli info server
기본 명령어 5가지
# 데이터 저장
SET name "Alice"
# OK
# 데이터 조회
GET name
# "Alice"
# 데이터 삭제
DEL name
# (integer) 1
# 키 존재 확인
EXISTS name
# (integer) 0
# 키 개수 확인
DBSIZE
이 다섯 개만 손에 익으면 Redis의 80%는 끝납니다. 더 많은 명령어가 궁금하면 Redis 명령어 레퍼런스에서 검색해 볼 수 있어요.
클라이언트 라이브러리 — Redis와 앱을 잇는 케이블
실무에서는 redis-cli로만 일하지 않아요. 애플리케이션 코드 안에서 Redis를 호출하는 도구가 클라이언트 라이브러리입니다.
회사 비유로 — Redis 사물함과 우리 앱 사이를 잇는 표준 케이블이에요. 이 케이블이 우리 코드의 메서드 호출을 Redis 명령어로 자동 변환해 보냅니다.
SQL ORM과의 결정적 차이
| 구분 | SQL ORM (Hibernate·Sequelize 등) | Redis 클라이언트 |
|---|---|---|
| 역할 | SQL 쿼리 추상화 | Redis 명령어 직접 매핑 |
| 필요 지식 | SQL 없이도 가능 | Redis 명령어 반드시 알아야 |
| 예시 호출 | findAll({ where: { name: 'Alice' } }) | client.get('name') → GET name |
여기서 정말 중요한 시험 함정 — Redis 클라이언트 라이브러리는 ORM이 아닙니다. 단순히 명령어를 그대로 매핑하는 얇은 래퍼예요. client.get('name')을 호출하면 그게 그대로 Redis 서버에 GET name 명령으로 전송됩니다. 그래서 Redis 명령어를 모르면 라이브러리도 못 쓴다는 게 결정적 차이예요.
언어별 주요 라이브러리
| 언어 | 라이브러리 |
|---|---|
| Node.js | node-redis, ioredis |
| Java | Lettuce(권장), Jedis |
| Python | redis-py |
| Go | go-redis |
Java는 두 라이브러리(Lettuce·Jedis) 모두 표준이라 시험에 자주 나오는데 — Lettuce가 비동기·리액티브 지원으로 최근 표준이에요. 자세한 Java/Spring 통합은 8편에서 풀어 갑니다.
node-redis 기본 사용 (TypeScript)
import { createClient } from 'redis';
// 클라이언트 생성·연결
const client = createClient({
socket: {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || '6379'),
},
password: process.env.REDIS_PASSWORD,
});
client.on('error', (err) => console.log('Redis Client Error', err));
await client.connect();
// 기본 명령어 사용
await client.set('name', 'Alice'); // → SET name Alice
const value = await client.get('name'); // → GET name
await client.del('name'); // → DEL name
console.log(value); // 'Alice'
> 한 줄 정리 — 클라이언트 라이브러리는 ORM이 아니라 얇은 케이블. Redis 명령어를 알아야 라이브러리도 잘 쓴다.
키-값 데이터 모델
Redis의 모든 데이터는 키-값(key-value) 봉투로 저장돼요. 키는 항상 문자열, 값은 데이터 타입에 따라 다양합니다.
# 단순 문자열 값
SET users:123:name "Alice"
SET users:123:email "alice@example.com"
SET sessions:token123 "userId:123"
키 네이밍 베스트 프랙티스
키 이름은 자유지만, 콜론(:)이나 해시(#) 로 계층을 표현하는 관습이 표준이에요. 회사 비유로 — 봉투에 적는 분류 라벨링 규칙입니다.
user:1000 → 사용자 ID 1000의 데이터
users:usernames → 모든 사용자명 집합
items#a1 → 아이템 ID a1의 데이터
sessions#token123 → 세션 토큰 데이터
items:views#itemId → 특정 아이템의 조회수
원칙은 셋이에요.
- 간결하게 — 짧고 의미 있는 키
- 일관성 — 전체 코드베이스에서 같은 패턴
- 헬퍼 함수로 중앙화 — 키 문자열을 직접 적지 말고 함수로 생성, 오타 방지
// keys.ts — 키 생성 헬퍼 함수
export const usersKey = (userId: string) => `users#${userId}`;
export const sessionsKey = (sessionId: string) => `sessions#${sessionId}`;
export const itemsKey = (itemId: string) => `items#${itemId}`;
export const userLikesKey = (userId: string) => `users:likes#${userId}`;
export const itemsViewsKey = (itemId: string) => `items:views#${itemId}`;
여기서 시험 함정이 하나 있어요. 키 이름은 자유지만 한 번 정한 패턴은 절대 바꾸기 어렵습니다. 운영 중인 시스템에서 키 패턴을 바꾸려면 모든 데이터를 마이그레이션해야 해요. 그래서 처음부터 신중하게 정해야 합니다.
데이터 타입 7종 — 큰 그림 먼저
Redis는 7가지 데이터 타입을 지원해요. 각각 자기 자리가 명확합니다. 자세한 사용법은 2편에서 풀고 여기선 큰 그림만 잡고 갑시다.
| 데이터 타입 | 설명 | 주요 사용 사례 |
|---|---|---|
| String | 문자열·숫자·바이너리 | 캐싱·카운터·세션 |
| Hash | 필드-값 쌍의 맵 | 객체·엔티티 저장 |
| List | 순서 있는 문자열 (이중 연결 리스트) | 시계열·큐 |
| Set | 고유 문자열의 비순서 집합 | 태그·관계·중복 방지 |
| Sorted Set | 스코어 기반 정렬 집합 | 리더보드·순위 |
| HyperLogLog | 근사 고유 개수 추정 | UV(고유 방문자) 추적 |
| Stream | 시계열 이벤트 로그 | 메시지 큐·이벤트 소싱 |
여기서 시험 단골 — 리더보드는 거의 100% Sorted Set, 고유 방문자 수는 HyperLogLog, 객체 한 덩어리는 Hash. 이 매핑을 외워두면 시나리오 문제 절반이 풀립니다.
> 한 줄 정리 — Redis는 7가지 자료 구조를 그대로 노출해 각 자리에 맞게 쓰게 한다. 데이터 타입 선택이 곧 설계.
운영에서 절대 피해야 할 함정 4가지
1. KEYS * 사용 금지
# 절대 사용 금지 (운영 환경)
KEYS * # 모든 키 조회 — 전체 DB 블로킹
# 대신 SCAN 사용
SCAN 0 COUNT 100 # 페이지 단위 안전 조회
SCAN 0 MATCH user:* COUNT 100 # 패턴 매칭과 함께
KEYS *는 단일 스레드 Redis를 통째로 멈춥니다. 100만 키가 있으면 그 동안 아무 요청도 못 받아요. 운영 환경에서는 절대 금지, 대신 SCAN으로 페이지 단위 조회.
2. TTL 없이 무한정 저장
Redis는 메모리 기반이라 무한정 저장하면 메모리 고갈로 서비스가 죽어요. 임시 데이터에는 TTL(만료 시간)을 반드시 설정합니다.
SET cache:data "value" EX 3600 # 1시간 후 자동 삭제
3. 직렬화·역직렬화 누락
Redis는 모든 값을 문자열로 저장해요. 객체를 그대로 던지면 [object Object] 같이 깨집니다.
// 잘못된 방법 — [object Object]로 저장됨
await client.set('user', { name: 'Alice' });
// 올바른 방법 — JSON 직렬화
await client.set('user', JSON.stringify({ name: 'Alice' }));
const user = JSON.parse(await client.get('user'));
4. 클라이언트 라이브러리를 ORM처럼 오해
위에서 짚었듯 — Redis 클라이언트는 ORM이 아닙니다. Redis 명령어를 먼저 익히고, 그 위에 라이브러리 사용법을 얹는 순서가 정답이에요.
시험 직전 한 번 더 — 자주 헷갈리는 함정 모음
여기까지가 Redis 1편의 핵심입니다. 시험 직전·실무 실수 방지를 위한 압축 노트로 마무리할게요.
- Redis = Remote Dictionary Server, 인메모리 키-값 DB
- 빠른 이유 3가지 — 인메모리 저장 + 단순 자료 구조 + 기능 미니멀리즘
- RAM 접근(~100ns) vs 디스크 접근(~10ms) = 약 100,000배 차이
- Redis는 SQL DB가 아님 — JOIN·복잡 쿼리·다중 테이블 트랜잭션 없음 (의도된 설계)
- 한계 — 메모리 크기 제한, 제한된 쿼리, 기본 영속성 없음
- 기본 포트 6379 (시험·면접 단골)
- 영속성 — RDB 스냅샷 / AOF / 하이브리드 (4편에서 자세히)
- 클라이언트 라이브러리 = 얇은 케이블, ORM 아님 (Redis 명령어 알아야 사용)
- Java 표준 — Lettuce(비동기·리액티브) > Jedis
- 키 네이밍 — 콜론(
:) 또는 해시(#) 계층, 헬퍼 함수로 중앙화 - 키 패턴은 한 번 정하면 운영 중 변경 어려움
- 데이터 타입 7종 — String / Hash / List / Set / Sorted Set(리더보드) / HyperLogLog(UV) / Stream
- 객체 한 덩어리 = Hash, 리더보드 = Sorted Set, 고유 방문자 = HyperLogLog
- 운영 절대 금지 — **
KEYS *(전체 DB 블로킹), 대신 SCAN** - 임시 데이터에 TTL 필수 (
SET key value EX 3600) - Redis 값은 모두 문자열 — 객체는 JSON.stringify·JSON.parse 명시 처리
시리즈 다른 편
같은 시리즈의 다른 글들도 같은 친절 톤으로 묶어 정리되어 있어요.