본문으로 바로가기

Redis Cache

category DB/REDIS 2023. 8. 8. 16:46
  • 변하지 않는 데이터 or 업데이트 데이터 사용
  • 데이터 재사용 2번 이상일 경우 적용
  • In-memory 데이터 저장(RAM) 하여 서버 재 시작시 데이터 유실 (영속성위해 별도 설정 필요)

 

  1. 메모리 기반 데이터 저장: Redis는 데이터를 메모리에 저장하므로 매우 빠른 읽기 및 쓰기 성능을 제공. 이는 데이터를 디스크에 저장하는 전통적인 데이터베이스 시스템과 비교해 상당한 성능 차이를 만들어냄.
  2. 데이터 구조 지원: Redis는 단순한 키-값 저장소뿐만 아니라 다양한 데이터 구조를 지원. 주요 데이터 구조로는 문자열, 해시 맵, 리스트, 세트, 정렬된 세트 등이 있다. 이러한 데이터 구조는 각각 특정한 용도에 맞게 사용될 수 있음.
  3. 영속성: Redis는 메모리 기반 데이터베이스 이지만, 데이터의 지속성을 보장하기 위해 스냅샷 및 로그 기반의 백업 메커니즘을 제공. 이를 통해 시스템 장애 발생 시에도 데이터를 복구할 수 있음.
  4. 출판/구독 메커니즘: Redis는 메시지 브로커의 역할을 할 수 있어, 발행자가 메시지를 발행하면 여러 구독자가 해당 메시지를 받아볼 수 있는 메커니즘을 제공. 이를 통해 실시간 알림 시스템 등을 구현할 수 있음.
  5. 트랜잭션: Redis는 여러 명령을 하나의 트랜잭션으로 묶어 실행하거나, 다른 클라이언트의 동작에 의해 트랜잭션의 일부가 영향받는 것을 방지하기 위한 멀티-스레드 환경에서 안전한 트랜잭션을 제공.
  6. 클라이언트 라이브러리: Redis는 다양한 프로그래밍 언어에서 사용할 수 있는 클라이언트 라이브러리를 지원. 이를 통해 언어별로 쉽게 Redis를 조작할 수 있음.
  7. Lua 스크립팅: Redis는 내장된 Lua 인터프리터를 통해 서버 측에서 스크립트를 실행할 수 있게 해줌. 이를 통해 복잡한 작업을 단일 명령으로 실행하거나 사용자 정의 연산을 수행.

 

Redis Cache 활성화를 위한 Annotation

@EnableCaching

  • SpringBoot에 캐싱기능 사용 알림

@Cacheable

  • DB에서 데이터를 가져오는 메서드에 적용
  • Application으로 가져온 데이터를 Cache에 저장

@CachePut

  • DB의 데이터 업데이트가 있을 때 Redis Cache에 데이터를 업데이트
  • DB에서 PUT/PATCH와 같은 업데이트에서 사용

@CacheEvict

  • DB의 데이터 삭제가 있을 때 Redis Cache에 데이터를 삭제
  • DB에서 DELETE와 같은 삭제에서 사용

@CacheConfig

  • 클래스 단위로 캐시 설정을 동일하게 하고 싶을 때 사용

스프링 시작 class 에 @EnableCaching 적용

package com.example.springbootredisstarter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class SpringBootRedisStarterApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootRedisStarterApplication.class, args);
    }

}

application.yml

  • redis 접속 정보 입력
spring:
  redis:
    host: localhost
    port: 6379
  cache:
    type: redis

RedisCacheConfig.java

  • Domain 모델을 Serialize 해주기위해 필요
  • @EnableCaching 어노테이션으로 캐시를 활성화하고 캐시 정책을 설정함
  • cacheManager 객체를 앞으로 사용할 레디스 어노테이션에 명시해 주어야 함
@Configuration
@EnableCaching
public class RedisCacheConfig {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory cf) {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .entryTtl(Duration.ofMinutes(3L));

        return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(cf).cacheDefaults(redisCacheConfiguration).build();
    }
}

Service 사용법 예시

@Cacheable

  • DB에서 데이터를 가져오는 메서드에 적용
  • Application으로 가져온 데이터를 Cache에 저장

@CachePut

  • DB의 데이터 업데이트가 있을 때 Redis Cache에 데이터를 업데이트
  • DB에서 PUT/PATCH와 같은 업데이트에서 사용

@CacheEvict

  • DB의 데이터 삭제가 있을 때 Redis Cache에 데이터를 삭제
  • DB에서 DELETE와 같은 삭제에서 사용
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Override
    public Order createOrder(Order order) {

        return orderRepository.save(order);

    }

    @Override
    @Cacheable(value = "Order", key = "#orderId", cacheManager = "testCacheManager")
    public Order getOrder(Integer orderId) {
        return orderRepository.findById(orderId).orElseThrow(() -> new OrderNotFoundException("Order Not Found"));
    }

    @Override
    @CachePut(value = "Order", key = "#orderId", cacheManager = "testCacheManager")
    public Order updateOrder(Order order, Integer orderId) {
        /*
        order status 변화주기
        status: ready -> processing -> shipped -> delivered
            */

        Order orderObject = orderRepository.findById(orderId).orElseThrow(() -> new OrderNotFoundException("Order Not Found"));
        if (orderObject.getOrderStatus().equals("ready")) {
            orderObject.setOrderStatus("processing");
        } else if (orderObject.getOrderStatus().equals("processing")) {
            orderObject.setOrderStatus("shipped");
        } else if (orderObject.getOrderStatus().equals("shipped")) {
            orderObject.setOrderStatus("delivered");
        } else {
            throw new OrderStatusException("Order Status Cannot Change");
        }

        return orderRepository.save(orderObject);
    }

    @Override
    @CacheEvict(value = "Order", key = "#orderId", cacheManager = "testCacheManager")
    public void deleteOrder(Integer orderId) {

        Order orderObject = orderRepository.findById(orderId).orElseThrow(() -> new OrderNotFoundException("Order Not Found"));
        orderRepository.delete(orderObject);

    }

    @Override
    @Cacheable(value = "Order", cacheManager = "testCacheManager")
    public List<Order> getAllOrders() {
        return orderRepository.findAll();
    }
}

'DB > REDIS' 카테고리의 다른 글

4. REDIS Sentinel  (0) 2019.07.24
3. REDIS Replication (Master-Slave)  (0) 2019.07.24
2. REDIS 실행 및 명령어  (0) 2019.07.24
1. REDIS 설치 및 환경설정  (0) 2019.07.24