Spring Boot에서 Redis를 통합하는 실전 가이드

Spring Boot 애플리케이션에 Redis 통합하기

Redis는 인메모리 키-값 데이터 저장소로, Spring Boot 애플리케이션에서 캐싱 및 세션 관리 등에 활용됩니다. 이 글에서는 Spring Boot 프로젝트에 Redis를 통합하는 두 가지 주요 방법(어노테이션 기반 캐싱과 RedisTemplate을 이용한 수동 캐싱)에 대해 설명합니다.

프로젝트 설정 및 의존성

먼저 Spring Initializr를 사용하여 프로젝트를 생성하고, 다음과 같은 의존성을 추가합니다.

<project>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
    </dependencies>
</project>

Redis 연결 구성

애플리케이션 설정 파일(application.yml)에 Redis 서버 연결 정보를 정의합니다.

spring:
  redis:
    host: localhost
    port: 6379
    database:规章制度 0
    timeout: 2000ms
    jedis:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0

방법 1: 어노테이션 기반 캐싱

Spring의 캐싱 어노테이션을 사용하여 메서드 결과를 자동으로 캐싱할 수 있습니다.

캐시 키 생성기 구성

@Configuration
public class CacheKeyConfig {

    @Bean
    public KeyGenerator customKeyGenerator() {
        return (target, method, params) -> {
            StringBuilder keyBuilder = new StringBuilder();
            keyBuilder.append(target.getClass().getSimpleName());
            keyBuilder.append(".");
            keyBuilder.append(method.getName());
            if (params.length > 0) {
                keyBuilder.append(".");
                keyBuilder.append(params[0].toString());
            }
            return keyBuilder.toString();
        };
    }
}

Redis 캐시 관리자 구성

@Configuration
@EnableCaching
public class RedisCacheConfig {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory,
                                     FastJsonRedisSerializer<Object> serializer) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(serializer));

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

JSON 직렬화 처리

@Component
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {

    private final Class<T> typeParameter;
    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    public FastJsonRedisSerializer(Class<T> typeParameter) {
        this.typeParameter = typeParameter;
        ParserConfig.getGlobalInstance().addAccept("com.example.");
    }

    @Override
    public byte[] serialize(T object) {
        if (object == null) return new byte[0];
        return JSON.toJSONString(object, SerializerFeature.WriteClassName)
                .getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) {
        if (bytes == null || bytes.length == 0) return null;
        String jsonString = new String(bytes, DEFAULT_CHARSET);
        return JSON.parseObject(jsonString, typeParameter);
    }
}

캐싱 어노테이션 활용 예제

@RestController
@RequestMapping("/api/cache")
public class CacheDemoController {

    @Cacheable(value = "userCache", key = "#userId")
    @GetMapping("/users/{userId}")
    public User fetchUser(@PathVariable String userId) {
        // 데이터베이스 조회 로직 (실제 구현 시)
        return new User(userId, "사용자_" + userId);
    }

    @CacheEvict(value = "userCache", key = "#userId")
    @DeleteMapping("/users/{userId}")
    public String removeUserCache(@PathVariable String userId) {
        return "캐시 제거 완료: " + userId;
    }

    @CachePut(value = "userCache", key = "#user.id")
    @PutMapping("/users")
    public User updateUser(@RequestBody User user) {
        // 업데이트 로직
        return user;
    }
}

방법 2: RedisTemplate을 이용한 수동 캐싱

더 세밀한 제어가 필요할 때 RedisTemplate을 직접 사용할 수 있습니다.

RedisTemplate 구성

@Configuration
public class RedisTemplateConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory factory,
            FastJsonRedisSerializer<Object> serializer) {
        
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);
        template.afterPropertiesSet();
        return template;
    }
}

수동 캐싱 구현 예제

@RestController
@RequestMapping("/api/manual")
public class ManualCacheController {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @GetMapping("/data/{key}")
    public ResponseEntity<?> getData(@PathVariable String key) {
        Object cachedData = redisTemplate.opsForValue().get(key);
        
        if (cachedData != null) {
            return ResponseEntity.ok(cachedData);
        }
        
        // 캐시 미스 발생 시 원본 데이터 소스 조회
        Object freshData = fetchFromDataSource(key);
        if (freshData != null) {
            redisTemplate.opsForValue().set(key, freshData, 10, TimeUnit.MINUTES);
        }
        
        return ResponseEntity.ok(freshData);
    }

    @PostMapping("/data")
    public String storeData(@RequestParam String key, 
                           @RequestBody Object data) {
        // 원본 데이터 저장 후 캐시 갱신
        redisTemplate.opsForValue().set(key, data, 10, TimeUnit.MINUTES);
        return "데이터 저장 및 캐싱 완료";
    }

    private Object fetchFromDataSource(String key) {
        // 실제 데이터 소스 조회 로직
        return Map.of("id", key, "value", "새로운 데이터");
    }
}

성능 최적화 팁

  • 캐시 만료 시간(TTL)을 적절히 설정하여 데이터 신선도 유지
  • 대량 데이터 처리 시 파이프라이닝 활용
  • 캐시 키 설계 시 네임스페이스 접두사 사용 권장
  • 모니터링을 위해 캐시 히트/미스 비율 추적

이 가이드를 통해 Spring Boot 애플리케이션에 Redis를 효과적으로 통합하고, 성능 최적화에 활용할 수 있습니다.

태그: Spring Boot Redis 캐싱 데이터직렬화 Spring Cache

8월 28일 04:11에 게시됨