Spring Boot에서 Redis 설정

dalBeen·2023년 10월 3일
1

스프링

목록 보기
13/14

Redis Client란 Redis서버와 통신하도록 설계된 라이브러리나 도구

여기서 Jedis와 Lettuce는 자바에서 Redis서버와 통신하기 위한 Redis 클라이언트 라이브러리

원래 Jedis 를 많이 사용했으나 여러 가지 단점 (멀티 쓰레드 불안정, Pool 한계 등등..) 과 Lettuce 의 장점 (Netty 기반이라 비동기 지원 가능) 때문에 Lettuce 로 추세가 넘어감


스프링부트에서 Redis 사용하는 방법

redis 공통적인 세팅이 있음


1. build.gradle에 추가

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

2. applicaton파일에 설정

spring.redis.host=127.0.0.1
spring.redis.port=6379

3. @Configuration 설정

@Configuration
public class RedisConfig {

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

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

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(host, port);
    }
}

Redisrepository RedisTemplate CacheManager

RedisTemplate

  • RedisTemplate은 Spring Data Redis 프로젝트에서 제공하는 중심 클래스입니다.
  • Redis 서버와의 모든 통신을 처리합니다. 직접적인 연산이 필요한 경우나 복잡한 연산을 처리하는 경우에 주로 사용됩니다.
  • Redis와의 상호작용을 위한 저수준의 라이브러리로 볼 수 있습니다.

RedisRepository

  • RedisRepository는 Spring Data Redis 프로젝트의 일부로 제공되는 인터페이스입니다.
  • 객체를 Redis와 매핑하고, 이를 통해 객체 지향적으로 Redis의 데이터를 CRUD 작업할 수 있게 해줍니다.
  • Spring Data 프로젝트의 Repository 패턴을 따르며, 이 패턴은 데이터 저장소에 대한 추상화를 제공합니다.

CacheManager (특히 RedisCacheManager)

  • CacheManager는 Spring Framework의 캐싱 추상화를 위한 인터페이스입니다.
  • 여기에서 RedisCacheManager는 Redis를 백엔드로 사용하는 CacheManager의 구현체입니다.
  • @Cacheable, @CacheEvict 등의 어노테이션과 함께 사용되어 캐싱 동작을 자동화합니다.

정리

RedisTemplate과 RedisRepository는 Spring Data Redis 프로젝트에서 제공되는 라이브러리/인터페이스로, Redis와의 CRUD 작업을 수행할 수 있습니다. 이들을 사용하면 캐싱 기능을 수동으로 구현하는 것도 가능합니다.
CacheManager는 Spring의 캐싱 추상화를 위한 인터페이스로, 이를 통해 캐싱 동작을 자동화할 수 있습니다.


RedisRepository 사용방법

엔티티를 만들어 사용

@RedisHash(value="person")
public class Person {
    @Id
    private String id;
    private String name;
    
    @Indexed
    private String token;
    
    @TimeToLive
    private long ttl;
    
}
  • @RedisHash : value값은 keyspace가 되고 timeToLive를 추가하면 만료시간을 초단위로 설정가능(만료시간 X :-1L)

  • @Id : 키 값이 됨
    -> keyspace : {Id} 로 최종키로 저장됨
    -> null이면 랜덤값이 설정됨

  • @Indexed : 값으로 검색을 할 시에 추가한다
    -> Redis의 보조 인덱스를 생성하는 데 사용
    -> RDBMS에서 인덱스는 특정 열의 값을 기반으로 빠르게 데이터를 검색하기 위해 사용
    -> @Indexed 어노테이션이 붙은 필드는 Redis에 저장될 때 해당 필드를 기반으로 보조 인덱스가 생성
    ->다만, 인덱스를 추가하는 것은 저장 공간과 데이터를 추가/수정할 때의 추가 작업을 필요로 하기 때문에, 실제로 해당 필드로 검색 작업이 자주 일어나는 경우에만 @Indexed를 사용

  • @TimeToLive : 따라 필드를 만들어 만료시간을 설정할 수 있음


JpaRepository처럼 CrudRepository인터페이스를 상속받기

@Id 또는 @Indexed어노테이션을 적용한 프로퍼티들만 CrudRepository가 제공하는 findBy~ 구문 사용가능

public interface PersonRedisRepository extends CrudRepository<Person, String> {

    Optional<RefreshToken> findByToken(String token);

    Optional<RefreshToken> findById(String Id);
}

테스트

@SpringBootTest
public class RedisRepositoryTest {

    @Autowired
    private PersonRedisRepository repo;

    @Test
    void test() {
        Person person = new Person("Park", 20,"avscd",10000);

        // 저장
        repo.save(person);

        // `keyspace:id` 값을 가져옴
        repo.findById(person.getId());

        // Person Entity 의 @RedisHash 에 정의되어 있는 keyspace (people) 에 속한 키의 갯수를 구함
        repo.count();

        // 삭제
        repo.delete(person);
    }
}

간단 정리

  • Person키값은 Set자료구조이며, Member엔티티에 해당하는 모든 key를 갖고 있음
  • person : {id} 로 Hash자료구조임

RedisTemplate 사용방법

여러 다양한 데이터 구조를 제공

cf) RedisRepository와 같이 Spring Data Redis에서 제공하는 Repository 추상화는 기본적으로 Redis의 해시(Hash) 구조를 사용하여 Java 객체를 저장

//RedisConfiguration에 Bean추가
    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }
@SpringBootTest
public class RedisTemplateTest {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    void testStrings() {
        // given
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        String key = "stringKey";

        // when
        valueOperations.set(key, "hello");

        // then
        String value = valueOperations.get(key);
        assertThat(value).isEqualTo("hello");
    }


    @Test
    void testSet() {
        // given
        SetOperations<String, String> setOperations = redisTemplate.opsForSet();
        String key = "setKey";

        // when
        setOperations.add(key, "h", "e", "l", "l", "o");

        // then
        Set<String> members = setOperations.members(key);
        Long size = setOperations.size(key);

        assertThat(members).containsOnly("h", "e", "l", "o");
        assertThat(size).isEqualTo(4);
    }

    @Test
    void testHash() {
        // given
        HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
        String key = "hashKey";

        // when
        //hashOperations.put(key, "field1", "value1");
        hashOperations.put(key, "hello", "world");

        // then
        Object value = hashOperations.get(key, "hello");
        assertThat(value).isEqualTo("world");

        Map<Object, Object> entries = hashOperations.entries(key);
        assertThat(entries.keySet()).containsExactly("hello");
        assertThat(entries.values()).containsExactly("world");

        Long size = hashOperations.size(key);
        assertThat(size).isEqualTo(entries.size());
    }
}

Redis에서 key는 데이터 베이스내에서 각 해시값이고 그 내부의 set,string혹은 map으로 되어있는 것

1. opsForValue

Redis의 문자열 (String) 데이터 타입과 관련된 연산을 위한 메서드입니다.
예: set, get, increment 등의 기본 값 연산을 수행합니다.

2. opsForList

Redis의 리스트 (List) 데이터 타입과 관련된 연산을 수행합니다.
예: leftPush, rightPush, range 등의 리스트 연산을 수행합니다.

3. opsForSet

Redis의 세트 (Set) 데이터 타입과 관련된 연산을 수행합니다.
예: add, remove, isMember 등의 세트 연산을 수행합니다.

4. opsForZSet

Redis의 정렬된 세트 (Sorted Set, ZSet) 데이터 타입과 관련된 연산을 수행합니다.
예: add, rangeByScore, remove 등의 정렬된 세트 연산을 수행합니다.

5. opsForHash

Redis의 해시 (Hash) 데이터 타입과 관련된 연산을 수행합니다.
예: put, get, entries 등의 해시 연산을 수행합니다.


CacheManger 사용방법

1. @EnableCaching 을 SpringBootApplication클래스에 붙이기


2. CacheManger 빈 추가

//RedisConfig에 빈추가
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){
        RedisCacheConfiguration con=RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(redisConnectionFactory)
                .cacheDefaults(con)
                .build();
    }

3. 캐시기능을 적용할 곳 선정하여 @Cacheable붙이기

 @Cacheable(key = "#personId",value = CacheKey.KEY_PERSON)
 public PersonCache getPerson{(String personId){
	.....
}
  • @Cacheable

    • 캐시에 데이터있으면 메소드 실행하지 않고 값을 가져오고 캐시에 데이터가 없으면 메소드 실행하여 값을 저장

    • 캐시를 가져오는 메소드에 붙이는 어노테이션

    • key
      실제로 캐시 내에서 항목을 구분하는 키를 생성하는 방법을 나타냄

    • value (또는 cacheNames)
      어느 캐시 영역에 해당 항목이 저장되어야 하는지를 나타냄

    • condition
      메서드 결과가 캐시에 저장되기 전에 조건을 확인하는 SpEL 표현식입니다. 표현식의 결과가 true일 때만 캐싱이 수행됩니다.
      예: @Cacheable(value="books", condition="#name.length() < 32")

    • unless
      메서드 결과를 캐시에 저장하지 않아야 할 경우를 지정하는 SpEL 표현식입니다. 표현식의 결과가 true일 때, 캐싱이 수행되지 않습니다.
      예: @Cacheable(value="books", unless="#result.hardback")

    • sync
      여러 스레드에서 동시에 같은 키의 데이터를 캐시에 저장하는 것을 방지하기 위한 설정입니다. true로 설정하면, 동시에 캐시 미스가 발생한 경우 하나의 스레드만 실제 메서드를 호출하고 결과를 캐시합니다.
      예: @Cacheable(value="books", sync=true)

    • cacheManager
      사용할 CacheManager의 빈 이름을 지정합니다. 여러 개의 CacheManager가 있는 경우에 유용합니다.

  • @CachePut

    • CacheKey.KEY_PERSON와 같이 해당 캐시 영역의 key에 대한 값을 수정할때

    • 캐시에 기존 값이 있더라도, 그 값을 조회하지 않고, 단순히 새로운 결과로 그 값을 덮어씀

    • condition
      메서드 결과가 캐시에 저장되기 전에 조건을 확인하는 SpEL 표현식입니다. 표현식의 결과가 true일 때만 캐싱이 수행됩니다.
      예: @CachePut(value="books", condition="#book.pageCount > 100")

    • unless
      메서드 결과를 캐시에 저장하지 않아야 할 경우를 지정하는 SpEL 표현식입니다. 표현식의 결과가 true일 때, 캐싱이 수행되지 않습니다.
      예: @CachePut(value="books", unless="#result.hardback")

    • cacheManager
      사용할 CacheManager의 빈 이름을 지정합니다. 여러 개의 CacheManager가 있는 경우에 유용합니다.

    • cacheResolver
      대상 캐시를 결정하는 CacheResolver의 빈 이름을 지정합니다. cacheNames 또는 value 대신에 사용될 수 있습니다.

    • keyGenerator
      사용할 KeyGenerator의 빈 이름을 지정합니다. key 속성과 함께 사용할 수 없습니다.

    • @CachePut는 메서드가 호출될 때마다 실행되므로, sync 속성과 같은 캐시 동기화에 관한 설정은 포함되지 않습니다


  • @CacheEvict
    • 캐시에 있는 데이터가 삭제된다
    • condition
      특정 조건이 true일 때만 캐시에서 항목을 제거합니다. 조건을 지정하는데 사용되는 SpEL 표현식입니다.
      예: @CacheEvict(value="books", condition="#isbn.length() > 10")
    • allEntries
      값이 true로 설정되면, 지정된 캐시의 모든 항목을 제거합니다. key와 함께 사용할 수 없습니다.
      예: @CacheEvict(value="books", allEntries=true)
    • beforeInvocation
      값이 true로 설정되면, 메서드 실행 전에 캐시에서 항목을 제거합니다. 기본적으로는 메서드가 성공적으로 완료된 후에 캐시에서 항목을 제거합니다.
      예: @CacheEvict(value="books", key="#isbn", beforeInvocation=true)
    • cacheManager
      사용할 CacheManager의 빈 이름을 지정합니다. 여러 개의 CacheManager가 있는 경우에 유용
profile
깊게 공부해보자

0개의 댓글