Redis

Spring RedisTemplate 자료구조별 사용법과 CLI 정리

수수한 인간 2025. 9. 29. 17:11

들어가면서

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

  1. RedisTemplate
    • 제네릭 타입 지정 가능 (RedisTemplate<String, Object> 등)
    • 다양한 직렬화 전략 적용 가능 (예: JSON 직렬화)
    • 복잡한 객체 저장/조회에 적합
  2. 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:count

2) 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를 활용한 세션 관리와 분산락 구현을 해보겠습니다.

예제 코드 주소