들어가면서
Redis는 처음 접할 때는 단순히 캐시 서버나 세션 관리 도구 정도로만 생각하기 쉽습니다.
하지만 Redis가 제공하는 다양한 자료구조를 활용하면 단순 캐시를 넘어 다양한 기능을 구현할 수 있습니다.
- 세션 만료 제어 (TTL vs TTI)
- 분산 환경에서의 락 처리
- 작업 큐와 예약 작업
- 랭킹 시스템
- UV/통계 집계
이번 글에서는 Redis의 기본 개념과 함께, Spring에서 RedisTemplate을 설정하고 각 자료구조별 사용하는 방법, CLI 명령어를 정리해보겠습니다.
👉 다음 편에서는 여기서 다룬 기본기를 바탕으로 실습 예제를 직접 만들어 보겠습니다.
1. Redis란?
Redis는 Remote Dictionary Server의 약자로, 인메모리 기반 Key-Value 저장소입니다.
이름처럼 원격에서 접근 가능한 인메모리 데이터베이스라는 점이 큰 특징입니다.
보통 캐시 서버로 가장 많이 활용됩니다.
애플리케이션 서버 내부 메모리에 캐시를 두면 속도는 빠르지만, 서버마다 데이터가 달라져 응답 결과가 일관되지 않을 수 있습니다.
Redis를 사용하면 여러 서버가 동일한 캐시/세션 데이터를 공유할 수 있어, 분산 환경에서도 안정적이고 일관된 응답을 제공합니다.
따라서 Redis는 단순 캐시뿐 아니라 세션 관리, 분산 락, 메시지 브로커, 실시간 통계 집계 등 다양한 상황에서 활용됩니다.
특징
- 고성능 및 속도
모든 데이터를 메모리에서 처리하기 때문에 디스크 기반 데이터베이스보다 훨씬 빠릅니다.
(평균 응답 시간: 1ms 미만)
→ 예: 초당 수천 건 이상의 요청이 들어오는 API 호출 횟수 카운터 - 다양한 자료구조
String, List, Hash, Set, Sorted Set, Bitmap, HyperLogLog, Stream 등 다양한 자료구조를 지원합니다.
→ 예: 게시글 조회수(String), 사용자 프로필(Hash), 대기열(List), 인기 검색어(ZSet) - 싱글 스레드(Single-Threaded)
하나의 메인 스레드로 모든 명령을 순차 처리하기 때문에 원자성(Atomicity)이 보장됩니다.
덕분에 Race Condition을 거의 신경 쓰지 않아도 됩니다.
(단, 시간이 오래 걸리는 명령어 사용은 성능에 주의해야 합니다.)
→ 예: 동시성 제어가 필요한 분산 락 구현 - 영속성 (Persistence)
인메모리 특성상 데이터가 휘발될 수 있으므로, 디스크 저장 방식을 지원합니다.- RDB (Redis Database): 특정 시점의 데이터 스냅샷 저장
- AOF (Append Only File): 모든 쓰기/갱신 명령을 로그 파일로 기록
→ 예: 서버 재시작 후에도 캐시 데이터 복원
- 복제 및 고가용성
Master-Replica 구조를 통한 복제(Replication)로 읽기 부하를 분산하고 안정성을 높일 수 있습니다.
또한 Redis Sentinel, Redis Cluster를 활용하면 자동 장애 조치(Fail-over)와 데이터 분산(샤딩)까지 가능합니다.
→ 예: 대규모 트래픽 환경에서 무중단 서비스 운영 - Pub/Sub 지원
발행/구독(Publish/Subscribe) 메시징 모델을 지원합니다.
→ 예: 실시간 알림, 채팅 시스템
RDBMS와 비교
| 구분 | Redis (NoSQL, Key-Value Store) | RDBMS (관계형 데이터베이스) |
|---|---|---|
| 데이터 저장 방식 | 인메모리(In-Memory): RAM에 데이터를 저장하여 디스크 접근이 불필요 | 디스크 기반: 디스크(HDD/SSD)에 데이터를 저장 (일부 데이터는 메모리 캐싱) |
| 주요 목적 | 캐시, 세션 관리, 순위표, 메시지 브로커 등 빠른 읽기/쓰기 및 실시간 처리 | 영구적인 데이터 저장, 트랜잭션 보장, 데이터 무결성 유지 |
| 속도 | 매우 빠름 (밀리초 미만). 메모리에서 직접 처리 | 비교적 느림. 디스크 I/O 발생 및 복잡한 쿼리(Join) 처리 시간 소요 |
| 데이터 모델 | Key-Value 구조. 다양한 자료구조(List, Set, Hash 등) 지원 | 테이블 기반의 정형화된 구조. 데이터 간 관계(Relationship) 명시 |
| 스키마(Schema) | 유연함/없음 (Schema-less). 데이터 구조 변경에 유연 | 명확함/고정됨. 데이터 삽입 시 엄격한 스키마 준수 |
| 트랜잭션 | 제한적 (주로 단일 명령 단위의 원자성). ACID 전체 준수는 어려움 | 강력한 ACID (원자성, 일관성, 격리성, 영속성) 보장. 복잡한 트랜잭션 처리 가능 |
| 확장성 | 수평 확장(Scale-out) 용이 (클러스터링, 샤딩을 통해 노드 추가) | 수직 확장(Scale-up) 위주 (서버 성능 향상). 수평 확장은 복잡하고 어려움 |
👉 정리하면, Redis는 속도와 확장성이 중요한 영역에 적합하고,
RDBMS는 데이터 무결성과 영속성이 중요한 영역에 적합합니다.
2. Spring에서 RedisTemplate 사용하기
Spring Boot에서는 Spring Data Redis 모듈을 통해 Redis와 쉽게 연동할 수 있습니다.
내부적으로는 Redis 클라이언트를 사용하는데, 최근에는 Lettuce(Netty 기반, 비동기/멀티스레드 지원)가 기본이며, 예전에는 Jedis도 많이 사용되었습니다.
1) 의존성 추가
maven 기준:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>2) 설정파일 추가
properties 설정
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.database= 0자바 설정 파일
@Configuration
public class RedisConfig {
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory cf) {
return new StringRedisTemplate(cf); // 키/값 모두 String
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory cf) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(cf);
// Key 직렬화: String
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// Value 직렬화: JSON
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}3) RedisTemplate vs StringRedisTemplate
- RedisTemplate
- 제네릭 타입 지정 가능 (RedisTemplate<String, Object> 등)
- 다양한 직렬화 전략 적용 가능 (예: JSON 직렬화)
- 복잡한 객체 저장/조회에 적합
- StringRedisTemplate
- Key, Value 모두 String 직렬화에 특화
- 단순 문자열 데이터 처리에 적합
- opsForValue(), opsForHash() 등 API 사용법은 동일
👉 일반적으로 문자열 위주의 캐시라면 StringRedisTemplate을 쓰고,
객체 직렬화까지 필요하다면 RedisTemplate을 설정해서 사용합니다.
Redis 자료구조별 CLI 및 사용 방법
1) String
- 설명: 가장 기본적인 Key-Value 구조 (문자열, 숫자 저장 가능)
- 활용 사례: 세션 토큰, API 호출 카운터, 플래그 값
Java (RedisTemplate)
redisTemplate.opsForValue().set("login:count", "1", Duration.ofMinutes(10));
redisTemplate.opsForValue().increment("login:count");
String count = redisTemplate.opsForValue().get("login:count");
Assertions.assertEquals(count, "2");CLI
SET login:count "1" EX 600
INCR login:count
GET login:count2) List
- 설명: 삽입 순서를 보장하는 자료구조 (큐/스택 모두 구현 가능)
- 활용 사례: 작업 대기열, 최근 로그 기록
Java (RedisTemplate)
ListOperations<String, String> listOperations = redisTemplate.opsForList();
// 오른쪽 삽입
listOperations.rightPush("queue:tasks", "task1");
listOperations.rightPush("queue:tasks", "task2");
// 왼쪽에서 꺼내기 (FIFO 큐)
String task1 = listOperations.rightPop("queue:tasks"); // "task1"
String task2 = listOperations.rightPop("queue:tasks"); // "task1"
Assertions.assertEquals(task1, "task2");
Assertions.assertEquals(task2, "task1");CLI
RPUSH queue:tasks "task1" 오른쪽 queue:tasks에 "task1" 삽입
RPUSH queue:tasks "task2" 오른쪽 queue:tasks에 "task2" 삽입
LPOP queue:tasks 왼쪽 리스트 꺼내기
LPOP queue:tasks 왼쪽 리스트 꺼내기3) Hash
- 설명: 하나의 키에 여러 필드와 값을 저장 (JSON 객체와 유사)
- 활용 사례: 사용자 프로필, 상품 정보, 설정 값 저장
Java (RedisTemplate)
HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
// 저장
hashOperations.put("user:1001", "name", "Alice");
hashOperations.put("user:1001", "age", "30");
// 조회
String name = hashOperations.get("user:1001", "name");
Map<String, String> user = hashOperations.entries("user:1001");
Assertions.assertEquals(name, "Alice");
Assertions.assertEquals(user, Map.of("name","Alice","age","30"));CLI
HSET user:1001 name "Alice"
HSET user:1001 age "30"
HGET user:1001 name # "Alice"
HGETALL user:1001 # 모든 필드 조회4) Set
- 설명: 중복 없는 집합 (합집합/교집합/차집합 지원)
- 활용 사례: 권한 관리, 태그, 좋아요 누른 사용자 목록
Java (RedisTemplate)
SetOperations<String, String> ops = redisTemplate.opsForSet();
// 저장
ops.add("team:dev", "alice", "bob");
// team:dev 조회
Set<String> members = ops.members("team:dev");
// team:dev, team:test 교집합 조회
Set<String> common = ops.intersect("team:dev", "team:test");
Assertions.assertEquals(members, Set.of("alice","bob"));
Assertions.assertEquals(common, Set.of());CLI
SADD team:dev "alice" "bob"
SMEMBERS team:dev # ["alice","bob"]
SINTER team:dev team:test # 교집합5) ZSet (Sorted Set)
- 설명: 점수(score)를 기준으로 자동 정렬되는 집합
- 활용 사례: 랭킹 시스템, 인기 검색어, 지연 큐
Java (RedisTemplate)
ZSetOperations<String, String> ops = redisTemplate.opsForZSet();
// 저장
ops.add("ranking", "alice", 100);
ops.add("ranking", "bob", 80);
// alice 점수 20 증가
ops.incrementScore("ranking", "alice", 20);
// 1, 2등 조회
Set<String> top = ops.reverseRange("ranking", 0, 1);
Assertions.assertEquals(top, Set.of("alice","bob"));CLI
ZADD ranking 100 "alice"
ZADD ranking 80 "bob"
ZINCRBY ranking 20 "alice"
ZREVRANGE ranking 0 1 WITHSCORES # 상위 2명6) Bitmap
- 설명: 비트 단위로 데이터를 저장/조회 (메모리 효율적)
- 활용 사례: 출석 체크, 로그인 여부, 특정 기능 플래그
Java (RedisTemplate)
ValueOperations<String, String> ops = redisTemplate.opsForValue();
// 1001번 유저 출석 체크
ops.setBit("attendance:20250922", 1001, true);
// 조회
Boolean present = ops.getBit("attendance:20250922", 1001);
Assertions.assertEquals(present, true);CLI
SETBIT attendance:20250922 1001 1
GETBIT attendance:20250922 1001 # 1 (true)
BITCOUNT attendance:20250922 # 출석자 수7) HyperLogLog
- 설명: 확률적 자료구조, 고유 값(Unique Count) 추정에 최적화 (오차 1% 이내)
- 활용 사례: UV(Unique Visitor) 집계, 대규모 이벤트 참여자 수 추정
Java (RedisTemplate)
HyperLogLogOperations<String, String> ops = redisTemplate.opsForHyperLogLog();
// 저장
ops.add("uv:20250922", "user1");
ops.add("uv:20250922", "user2");
// 조회
Long uv = ops.size("uv:20250922");
Assertions.assertEquals(uv, 2);CLI
PFADD uv:20250922 "user1"
PFADD uv:20250922 "user2"
PFCOUNT uv:20250922 # 고유 사용자 수마무리
이번 글에서는 Redis의 기본 개념과 Spring에서 RedisTemplate을 설정하고 사용하는 방법을 정리하였고
그리고 자료구조별 특징과 활용 예시를 코드와 CLI 명령어와 함께 정리하였습니다.
👉 자료구조별 활용 예시
- String → 세션, 카운터
- Hash → 사용자 프로필, 상품 정보
- List → 작업 대기열, 로그
- Set → 권한 관리, 태그
- ZSet → 랭킹, 인기 검색어
- Bitmap → 출석 체크, 로그인 여부
- HyperLogLog → UV 추정치
다음편에서는 Redis를 이용한 TTL vs TTI를 활용한 세션 관리와 분산락 구현을 해보겠습니다.
'Redis' 카테고리의 다른 글
| Redis 분산락 정리(직접 구현 vs Redisson 비교) (0) | 2025.11.02 |
|---|---|
| Redis 데이터 만료 전략 개념 및 예제 (Feat: TTL, TTI) (0) | 2025.10.12 |