본문 바로가기

Spring Boot/Cache

분산 캐시의 이해와 Redis : Redis 개요와 주요 특징

뭐가 이렇게 어렵냐?

 

 - Redis의 핵심 구조와 작동 원리

 - 인메모리 기반 고성능 저장 방식의 장점

 - 다양한 데이터 구조(String, Hash, List, Set 등)의 특징 및 활용 사례

 - 영속성(Persistence) 옵션의 동작 방식을 이해하고 선택하기

 - 클러스터링과 고가용성 구조를 통해 Redis가 안정적으로 운영되는 원리

 


Redis 개요

Redis는 Remote Dictionary Server의 약자임

데이터를 메모리(RAM)에 저장하는 초고속 인메모리 데이터 저장소라고 함

디스크 기반 데이터베이스보다 훨씬 빠르게 데이터를 읽고 쓸 수 있다

캐시, 세션 저장소, 실시간 순위 집계 등 다양한 분야에서 사용된다

 

 

1. 인메모리 데이터 저장 구조

Redis는 모든 데이터를 메모리에 저장하고, 필요할 때 디스크에 백업한다

즉 속도는 메모리급, 안정성은 디스크급으로 설계되어 있음

Redis 시작

 

항목 설명
저장 위치 RAM(인메모리)
데이터 접근 속도 매우 빠름(매우)
백업 방식 RDB, AOF 등 디스크 기반 옵션 제공
활용 사례 캐시, 세션 관리, 순위 시스템, 실시간 알림 등

 

* Redis는 단순 캐시가 아니라, 빠른 데이터 접근이 필요한 모든 상황에서 활용 가능한 고성능 데이터 저장소임

 

 

2. 싱글 스레드 기반 고성능 구조

Redis는 단일 스레드(Event Loop) 구조로 동작함

즉, 한번에 한번만 처리하지만 논블로킹 I/O 모델을 통해 초당 수십만 건의 요청을 처리할 수 있음

Redis는 단일 스레드지만 논블로킹 I/O임

 

장점 설명
경쟁 조건 없음 하나의 스레드만 실행되므로 락(Lock) 불필요
Context Switching 없음 CPU 오버헤드 최소화
높은 처리량 수십만 QPS(Queries Per Second) 가능

 

* DB는 다중 스레드로 병렬 처리하지만, Redis는 단일 스레드로도 더 높은 효율을 낼 수 있다

 


Redis의 주요 데이터 구조

Redis는 단순 문자열 캐시를 넘어, 다양한 데이터 구조를 지원하고 있음

이 덕에 복잡한 데이터 조작도 별도의 DB없이 메모리에서 즉시 처리할 수 있음

 

 

1. 데이터 구조 요약

타입 설명 주요 활용 사례
String 기본 데이터 타입(문자열, 숫자 등) 세션 토큰, 사용자 이름 등
List 순서가 있는 데이터 목록 메시지 큐, 최근 검색 기록 등
Set 중복 없는 조합 좋아요 사용자 목록, 태그 관리
Sorted Set(ZSet) 점수 기반 정렬 집합 랭킹 시스템, 점수 집계
Hash Key - Value 쌍의 객체형 데이터 사용자 프로필, Json 구조
Bitmap / HyperLogLog 비트연산 또는 통계 집계용 방문자 수, 클릭 수

 

 

2. 예제 명령어

	/**
	 * 1) String(단일 값)
	 * - 가장 기본 타입 : key - > string value
	 * - 대표 사용 : 간단한 사용 값, 토큰, 카운터(증감은 INCR / DECR)
	 * - 주의 : 덮어쓰기(SET)는 기존 값이 사라짐. TTL이 필요하다면 SET key value EX <sec> 사용
	 */
	
	// 사용자 1의 이름을 Alice로 저장하기
	SET user:1:name "Alice" // 새로 저장 또는 덮어쓰기
	// 저장된 이름 읽기
	GET user:1:name // "Alice" 출력
	
	/**
	 * 참고 : 만료시간(예를 들어 60초)까지 함께 저장하려면
	 * SET user:1:name "Alice" EX 60
	 */
	
	/**
	 * 주의 : 숫자 카운터의 경우 SET 대신 INCR/DECR 권장
	 * INCR page:view:home
	 * -> 1씩 증가함
	 * 
	 * GET page:view:home
	 * -> 1 출력됨
	 */

 

와 ㅈㄴ 재밌어

 

 

	/**
	 * 2) List(순서가 있는 큐 / 스택)
	 * - 대표 사용 : 최근 기록(타임라인), 작업 큐(왼쪽 PUSH, 오른쪽은 POP)
	 * - LPUSH : 왼쪽(머리)에 삽입 -> 새 값이 앞에 옴(최근 항목이 인덱스 0)
	 * - LRANGE : start stop : 구간 조회(stop = -1이면 끝까지)
	 * -주의 : 길이 무한 증가 방지를 위해 Trim 또는 maxlen 정책을 병행함
	 */
	
	// 최근 검색어를 왼쪽에 차례대로 삽입하기 (가장 최근이 맨 앞)
	LPUSH recent:search "Redis"
	// ["Redis"]
	LPUSH recent:search "Spring"
	// ["Spring", "Redis"]
	
	// 전체 목록 조회(0부터 끝까지)
	LRANGE recent:search 0 -1
	// ["Spring", "Redis"]
	
	/**
	 * 최근 N개만 유지하고 싶다면 : LTRIM recent:search 0 19
	 * -> 상위 20개만 보존함
	 */

 

	/**
	 * 3) Set(중복 없는 조합)
	 * - 대표 사용 : 좋아요한 사용자의 집합, 팔로워 목록 등 "중복 제거"가 필요한 경우
	 * - SADD : 원소 추가(중복 자동 제거)
	 * - SMEMBERS : 모든 원소 조회하기(순서 보장 x)
	 * - SISMEMBER : 특정 원소 포함 여부 체크(0(1))
	 */
	
	// 게시글 100번을 좋아요한 사용자 집합에 1, 2, 3 추가
	SADD like:post:100 user:1 user:2 user:3
	// {user:1, user:2, user:3}
	
	// 좋아요 사용자 전체 조회(순서 없이)
	SMEMBERs like:post:100
	// {"user:2", "user:1", "user:3"}와 같이 순서없음
	
	/**
	 * 사용자 2가 좋아요를 했는지 확인하기
	 * SISMEMBER like:post:100 user:2
	 * 1(참), 0(거짓)
	 */

 

	/**
	 * 4) Sorted Set(정렬된 집합, 점수(score) + 값)
	 * - 대표 사용 : 랭킹, 점수판, 만료시각을 score로 쓰는 일정 정렬 등
	 * - ZADD score member: score 기준 오름차순 정렬
	 * - ZRANGE start stop WITHSCORES: 인덱스 구간 조회(낮은 점수 -> 높은 점수)
	 * - ZREVRANGE: 높은 점수 -> 낮은 점수(내림차순 랭킹에 유용함)
	 */
	
	// 랭킹 집합에 점수와 이름 추가하기(score가 낮을수록 앞임)
	ZADD ranking 100 "Alice"
	// {"Alice":100}
	ZADD ranking 200 "Bob"
	// {"Alice":100, "Bob":200}
	
	// 오름차순(낮은점수 -> 높은점수)으로 조회하기 + 점수도 함께
	ZRANGE ranking 0 -1 WITHSCORES
	// ["Alice","100"]
	
	/**
	 * 일반적인 "1등이 점수 높은 사람"이라면, ZREVRANGE 사용하기
	 * ZREVRANGE ranking 0 -1 WITHSCORES
	 * ["Bob","200","Alice","100"]
	 */

 

	/**
	 * 5) Hash(필드가 여러개인 객체)
	 * - 대표 사용 : 사용자 / 상품처럼 속성이 여러개인 "한 개체"를 하나의 키에 저장
	 * - HSET key field value ... : 여러 필드를 한번에 설정하기
	 * - HGETALL key : 모든 필드/값 조회하기 (갯수가 많으면 HSCAN 고려하기)
	 * - HGET key field : 단일 필드 조회하기
	 */
	
	// user:1 해시에 name, age 필드 설정하기
	HSET user:1 name "Alice" age 25
	// {name:"Alice", age:"25"} -> 숫자도 문자열로 저장됨
	
	// 전체 필드 조회하기(필드와 값이 번갈아서 나옴)
	HGETALL user:1
	// ["name","Alice","age","25"] 와 같이 번갈아서 나옴
	
	/**
	 * 부분 조회 : HGET user:1 age
	 * "25" 가 출력됨
	 * 주의 : 필드 수가 매우 많으면 HGETALL 대신 HSCAN으로 분할 조회가 안전하다!
	 */

 

* Redis는 데이터 타입이 다양하므로, 적절한 구조를 선택하는 것이 성능과 메모리 효율에 큰 영향을 미친다고 한다

 


Redis의 영속성(Persistence)

Redis는 인메모리 시스템이지만, 데이터를 잃지 않기 위해서 두가지 영속성 옵션을 제공한다고 함

 

1. RDB(Redis Database Snapshot)

 - 일정 주기로 전체 데이터를 스냅샷 형태로 디스크에 저장함

 - 서버 재시작시 마지막 스냅샷을 불러온다

save 900 1 # 900초(15분) 내 1회 이상 변경되면 저장하기
save 60 1000 # 1분 내 1000건이상 변경 시 저장하기

 

항목 설명
파일명 dump.rdb
장점 복원 속도 빠름, 백업이 용이함
단점 주기적 저장이라 최근 변경 데이터 손실 가능

 

 

2. AOF(Append Only File)

 - 모든 쓰기 명령(SET, LPUSH 등)을 순차적으로 파일에 기록한다

 - 장애가 발생하면 명령을 다시 실행해서 복구할 수 있음

appendonly yes
appendfsync everysec

 

항목 설명
파일명 appendonly.aof
장점 데이터 손실 최소화
단점 파일 크기가 커지고 복구 시간이 길다

 

 

3. RDB + AOF 혼합 전략

Redis는 두 방식을 병행하여, 속도와 안전성의 균형을 맞출 수 있음!

방식 특징
RDB(Redis Database Snapshot) 빠른 백업 및 복원
AOF(Append Only File) 안정적인 실시간 보존
혼합 고속성과 안정성을 동시에 확보 가능

 

* 실무 운영환경에서는 대부분 RDB + AOF를 병행해서 사용한다고 함

단, 개발 환경에서는 단순히 RDB만 설정해도 충분하다고 한다


Redis 클러스터링과 고가용성 구조

대규모 트래픽 환경에서 Redis는 클러스터 구조를 통해 성능과 안정성을 높일 수 있음

 

1. Redis 클러스터 구조

Redis 클러스터

 

구성요소 역할
Master Node 실제 데이터 저장 및 요청 처리
Replica Node Master 복제본 유지, 장애 시 승격됨(Failover)
Slot 데이터를 해시 기반으로 분산 저장함(0 ~ 16383 slot)

 

클러스터는 자동으로 데이터 샤딩(Sharding)을 수행하여 부하를 분산한다고 함

 

 

2. Sentinel 기반 고가용성

Sentinel은 Redis 서버의 상태를 모니터링하고, 장애가 발생하면 자동으로 복구(Failover) 해줌

Sentinel

 

구성 요소 설명
Sentinel Redis 인스턴스 상태 감시
Master 쓰기 처리 담당
Replica 읽기 처리 + 복제 유지
Failover 장애시 Replica를 Master로 승격함

 


* Redis는 단순 캐시뿐만 아니라 Pub/Sub, 메시지 큐, 세션 스토리지 등에도 자주 활용된다

* CPU가 많은 서버에서는 여러 Redis 인스턴스를 띄워 분산 실행하면 성능이 향상된다고 함

* TTL(Time To Live)를 반드시 설정해야 메모리 누수(Cache Leak)를 방지할 수 있다

* 모니터링 명령어 : INFO, MONITOR, SLOWLOG GET -> 이러한 명령어는 운영 중 필수 점검 항목임

 


정리

구분 내용
저장 구조 인메모리 기반 초고속 접근
처리 구조 싱글 스레드 기반 논블로킹 I/O
데이터 구조 String, Hash, List, Set, ZSet 등 다양함
영속성 RDB, AOF, 혼합 지원
확장성 / 가용성 클러스터링 및 Sentinel 구성 가능