Redis - 기초 개념과 적용

StrayCat·2026년 2월 26일

CS지식

목록 보기
11/32

Redis는 단순한 캐시가 아닙니다. 세션 저장소, 분산 락, 메시지 큐 등 다양한 역할을 수행할 수 있는 강력한 인메모리 데이터 저장소입니다.


Redis란?

Redis(Remote Dictionary Server)는 메모리 기반의 Key-Value 저장소입니다.
데이터를 디스크가 아닌 RAM에 저장하기 때문에 읽기/쓰기 속도가 매우 빠릅니다.

왜 Redis를 사용할까?

상황Redis 없이Redis 적용 후
인기 상품 조회 API매 요청마다 DB 쿼리첫 요청만 DB, 이후 캐시 반환
로그인 세션 관리DB에 세션 저장Redis에 저장, 빠른 조회
중복 요청 방지구현 복잡TTL 기반 간단히 처리
  • DB는 "정확하게 오래 보관해야 하는 데이터"
  • Redis는 "빠르게 자주 읽어야 하는 데이터" 를 담당

Redis가 지원하는 자료구조

  • String — 가장 기본. 단순 값, 카운터, 토큰 저장
  • List — 큐/스택 구조
  • Set — 중복 없는 집합
  • Sorted Set (ZSet) — 점수 기반 정렬, 랭킹 구현에 유용
  • Hash — 객체 형태 저장 (Java Map과 유사)

Redis 설치

Docker로 실행 (권장)

개발 환경에서는 Docker를 이용하는 것이 가장 간편합니다.

# Redis 컨테이너 실행 (포트 6379)
docker run -d \
  --name redis-local \
  -p 6379:6379 \
  redis:7.2

# 실행 확인
docker exec -it redis-local redis-cli ping
# PONG 응답이 오면 정상

macOS (Homebrew)

brew install redis
brew services start redis

Windows

Windows 환경에서는 공식적으로 Redis를 지원하지 않으므로, Docker Desktop 또는 WSL2 환경에서 실행하는 것을 권장합니다.


Spring Boot 3 프로젝트 설정

build.gradle 의존성 추가

dependencies {
    // Spring Data Redis (Lettuce 클라이언트 포함)
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    
    // 객체 직렬화를 위한 Jackson (Spring Boot에 기본 포함되어 있음)
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

Spring Boot 3에서는 Jedis 대신 Lettuce가 기본 Redis 클라이언트로 사용됩니다.
Lettuce는 비동기/논블로킹 방식을 지원하며, 멀티스레드 환경에서 커넥션을 공유할 수 있어 성능상 이점이 있습니다.

application.yml 설정

spring:
  data:
    redis:
      host: localhost
      port: 6379
      # password: yourpassword  # 비밀번호 설정 시 주석 해제
      # database: 0             # 기본값 0번 DB

Spring Boot 2.x까지는 spring.redis.* 였으나,
Spring Boot 3.x부터는 spring.data.redis.*로 네임스페이스가 변경되었습니다.
기존 설정을 그대로 사용하면 연결이 안 될 수 있으니 반드시 확인하세요.

Redis 설정 클래스

@Configuration
public class RedisConfig {

    @Value("${spring.data.redis.host}")
    private String host;

    @Value("${spring.data.redis.port}")
    private int port;

    /**
     * Redis 연결 정보를 담는 Factory Bean
     * Lettuce 클라이언트를 사용하여 연결을 맺습니다.
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(host, port);
    }

    /**
     * Redis에 Java 객체를 저장하기 위한 직렬화 설정
     * Key: String 타입으로 저장
     * Value: JSON 형태로 직렬화하여 저장 (사람이 읽을 수 있는 형태)
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory());

        // Key를 String으로 직렬화
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        // Value를 JSON으로 직렬화
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.activateDefaultTyping(
            LaissezFaireSubTypeValidator.instance,
            ObjectMapper.DefaultTyping.NON_FINAL
        );
        Jackson2JsonRedisSerializer<Object> serializer =
            new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);

        template.setValueSerializer(serializer);
        template.setHashValueSerializer(serializer);

        return template;
    }
}

RedisTemplate 사용법

RedisTemplate은 Redis의 다양한 자료구조에 접근하기 위한 핵심 클래스입니다.
각 자료구조별로 Operations 객체를 통해 접근합니다.

String 타입 — 가장 많이 사용하는 기본형

@Service
@RequiredArgsConstructor
public class RedisStringService {

    private final RedisTemplate<String, Object> redisTemplate;

    // 값 저장 (만료시간 없음)
    public void save(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    // 값 저장 + TTL 설정 (1시간 후 자동 삭제)
    public void saveWithTTL(String key, Object value) {
        redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);
    }

    // 값 조회
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    // 키 삭제
    public void delete(String key) {
        redisTemplate.delete(key);
    }

    // 키 존재 여부 확인
    public boolean exists(String key) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }
}

Hash 타입 — 객체 형태로 저장할 때

@Service
@RequiredArgsConstructor
public class RedisHashService {

    private final RedisTemplate<String, Object> redisTemplate;

    // Hash 필드 저장: HSET user:1 name "홍길동"
    public void saveField(String key, String field, Object value) {
        redisTemplate.opsForHash().put(key, field, value);
    }

    // 특정 필드 조회: HGET user:1 name
    public Object getField(String key, String field) {
        return redisTemplate.opsForHash().get(key, field);
    }

    // Hash 전체 조회: HGETALL user:1
    public Map<Object, Object> getAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }
}

Sorted Set — 랭킹 구현 예시

@Service
@RequiredArgsConstructor
public class RankingService {

    private final RedisTemplate<String, Object> redisTemplate;
    private static final String RANKING_KEY = "game:ranking";

    // 점수 추가/갱신: ZADD game:ranking 1500 "user123"
    public void addScore(String userId, double score) {
        redisTemplate.opsForZSet().add(RANKING_KEY, userId, score);
    }

    // 점수 높은 순으로 상위 10명 조회
    public Set<Object> getTopRankers() {
        return redisTemplate.opsForZSet()
            .reverseRange(RANKING_KEY, 0, 9); // 0~9 = 상위 10명
    }

    // 특정 유저 랭킹 조회 (0부터 시작, +1 하면 실제 순위)
    public Long getUserRank(String userId) {
        return redisTemplate.opsForZSet().reverseRank(RANKING_KEY, userId);
    }
}

Spring Cache + Redis

@Cacheable, @CacheEvict 등의 어노테이션으로 메서드 결과를 자동으로 캐싱할 수 있습니다.
직접 RedisTemplate을 조작하지 않아도 되기 때문에 코드가 훨씬 간결해집니다.

설정 추가

@Configuration
@EnableCaching  // 캐시 기능 활성화
public class CacheConfig {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(10))         // 기본 TTL: 10분
            .serializeKeysWith(
                RedisSerializationContext.SerializationPair
                    .fromSerializer(new StringRedisSerializer())
            )
            .serializeValuesWith(
                RedisSerializationContext.SerializationPair
                    .fromSerializer(new GenericJackson2JsonRedisSerializer())
            );

        return RedisCacheManager.builder(redisConnectionFactory)
            .cacheDefaults(config)
            .build();
    }
}

사용 예시

@Service
@RequiredArgsConstructor
public class ProductService {

    private final ProductRepository productRepository;

    /**
     * @Cacheable: 캐시에 데이터가 있으면 DB 조회 없이 캐시에서 반환
     * 캐시 키: "products::1" (캐시명::파라미터)
     */
    @Cacheable(value = "products", key = "#id")
    public ProductDto getProduct(Long id) {
        // 이 코드는 캐시 미스(처음 요청)일 때만 실행됨
        return productRepository.findById(id)
            .map(ProductDto::from)
            .orElseThrow(() -> new RuntimeException("상품을 찾을 수 없습니다."));
    }

    /**
     * @CachePut: 항상 메서드를 실행하고, 결과를 캐시에 저장/갱신
     */
    @CachePut(value = "products", key = "#id")
    public ProductDto updateProduct(Long id, ProductUpdateRequest request) {
        // 업데이트 로직
        return updatedProductDto;
    }

    /**
     * @CacheEvict: 캐시 삭제
     * allEntries = true 이면 "products" 캐시 전체 삭제
     */
    @CacheEvict(value = "products", key = "#id")
    public void deleteProduct(Long id) {
        productRepository.deleteById(id);
    }
}

세션 저장소로 활용하기

Spring Session + Redis를 함께 사용하면 HTTP 세션을 Redis에 저장할 수 있습니다.
서버가 여러 대일 때(수평 확장) 세션 공유 문제를 손쉽게 해결할 수 있습니다.

의존성 추가

implementation 'org.springframework.session:spring-session-data-redis'

설정

@Configuration
@EnableRedisIndexedHttpSession(maxInactiveIntervalInSeconds = 1800) // 30분
public class SessionConfig {
    // RedisConnectionFactory Bean만 있으면 자동으로 세션을 Redis에 저장합니다.
}

@EnableRedisHttpSession은 Spring Boot 3.x에서 deprecated 되고
@EnableRedisIndexedHttpSession이 권장됩니다.


TTL과 데이터 만료 전략

Redis에서 TTL(Time To Live)은 데이터 자동 삭제 시간을 의미합니다.
용도에 따라 적절한 TTL을 설정하는 것이 중요합니다.

// TTL 설정 예시
redisTemplate.opsForValue().set("token:user123", tokenValue, 30, TimeUnit.MINUTES);

// 남은 TTL 확인
Long remainingSeconds = redisTemplate.getExpire("token:user123", TimeUnit.SECONDS);

// TTL 갱신 (연장)
redisTemplate.expire("token:user123", 30, TimeUnit.MINUTES);
용도권장 TTL
이메일 인증 코드3~5분
로그인 세션30분~1시간
JWT Refresh Token7~30일
상품 목록 캐시5~10분
랭킹 데이터1~24시간

기타

Redis 7.x 주요 변화

Redis 7.0부터 Redis Functions, Multi-Part AOF 등이 도입되었습니다.
7.2 기준으로 안정성이 높아졌으므로, 신규 프로젝트라면 7.x 버전 사용을 권장합니다.

Redis Stack

Redis에 검색(RediSearch), 그래프(RedisGraph), JSON(RedisJSON) 기능이 추가된 Redis Stack을 활용하면 더 다양한 쿼리가 가능합니다. 단, 운영 환경에서의 라이선스 정책은 반드시 확인이 필요합니다 (2024년부터 Redis의 라이선스가 SSPL로 변경됨).

Valkey (Redis 오픈소스 포크)

2024년 Redis의 라이선스 변경으로 인해 Linux Foundation 주도 하에 Valkey라는 오픈소스 포크 프로젝트가 탄생했습니다. AWS ElastiCache, GCP Memorystore 등 클라우드 서비스도 Valkey를 지원하기 시작했습니다. 이 흐름은 알아 두는 것이 좋으며, Spring Data Redis는 Valkey와도 호환됩니다.

레거시 환경 참고

기존에 구축된 환경 중 상당수는 여전히 Redis 5.x~6.x, Spring Boot 2.x를 사용하고 있습니다.
이 경우 설정 네임스페이스가 spring.redis.*이며, @EnableRedisHttpSession을 사용합니다.
코드를 읽을 때 버전 차이를 인지하고 해석하면 혼란을 줄일 수 있습니다.

Spring Boot 3.x 마이그레이션 체크리스트

  • spring.redis.*spring.data.redis.* 로 변경
  • @EnableRedisHttpSession@EnableRedisIndexedHttpSession 권장
  • Jackson2JsonRedisSerializer 생성자 변경 (ObjectMapper를 직접 전달하는 방식으로)
  • Java 17 이상 필수

정리

Redis를 Spring Boot 3에서 활용하는 핵심 흐름은 다음과 같습니다.

  1. Docker로 Redis 실행
  2. spring-boot-starter-data-redis 의존성 추가
  3. application.ymlspring.data.redis.* 설정
  4. RedisConfig에서 직렬화 설정
  5. RedisTemplate 또는 @Cacheable 어노테이션으로 활용

단순한 캐시 저장소로 시작해서, 세션 저장소 → 분산 락 → 랭킹 시스템 순으로 범위를 넓혀가면 Redis를 깊이 이해할 수 있습니다.

profile
알면 좋은 것보단 잊어버리기 싫은 것들을 기록합니다.

0개의 댓글