Spring에서 Redis를 사용해보자

Fermion·2024년 1월 16일
0

What is Development

목록 보기
7/9

Redis란?

Redis는 in-memory 자료구조 저장소로 DB, Cache, Message Broker, Streaming Engine으로 사용된다.


Redis의 특징

Redis는 String, Hash, List, Set, Sorted Set, Bitmap, Hyperloglog, Geospatial Index, Stream 등의 자료구조를 제공한다.

Redis는 replication, Lua scripting, LRU eviction, transaction 기능 등을 내장하고 있다.

또한, 다양한 level의 on-disk persistence, Redis Sentinel을 통한 HA, Redis Cluster를 통한 자동 partitioning을 제공한다.


이러한 기능을 바탕으로 다음과 같은 유형의 atomic operation을 제공한다.

  • string에 append
  • hash에 있는 value의 increment
  • list에 element push
  • set intersection, union, difference 계산
  • sorted set에서 highest ranking member 찾기

성능을 위해서는 Redis를 in-memory dataset으로 사용하는 것이 좋다.

하지만 필요에 따라, Redis는 다음과 같이 data를 영속할 수 있다.

  • 주기적으로 dataset을 disk에 dump하기
  • 각 command를 disk-based log에 추가하기

Redis는 빠른 non-blocking synchronization과 net split에서의 partial resynchronization을 통한 auto-reconnection과 함께 asynchronous replication을 지원한다.


Redis는 또한 다음과 같은 기능을 제공한다.

  • Transaction
  • Pub/Sub
  • Lua scripting
  • Keys with a limited time-to-live
  • LRU eviction of keys
  • Automatic failover

Spring Redis Client의 종류

Redis에 연결하는 방법은 다음과 같다.

  • redis-cli를 통해 CLI로 사용
  • RedisInsight를 통해 GUI로 사용
  • 프로그래밍 언어의 libraray를 통해 사용

위 방법 중에서도 Java 언어를 이용한 client인 Jedis와 Lettuce의 특징은 다음과 같다.

Jedis

Jedis는 Redis에 내장된 client library로 성능과 편리함을 위해 개발되었다.

Jedis는 다른 Redis Java Client들에 비해 경량화되어 있어 적은 feature를 제공하지만 많은 양의 memory를 다룰 수 있다.

Jedis는 synchronous하게 동작한다.


Lettuce

Lettuce는 Non-blocking을 지원하는 Redis Java Client이다.

Lettuce는 Synchronous와 Asynchronous communication을 모두 지원한다.


Spring에서 Redis 활용

기존에는 Jedis가 Redis Java Client로 사용되었으나
비동기 방식이기에 성능적으로는 Lettuce가 우위에 있어
Spring Boot 2.0부터 Lettuce가 기본 client로 사용되고 있다.

Jedis의 경우 사용성에서 장점이 있고
Lettuce의 경우 성능면에서 장점이 있다고 볼 수 있다.

각 방법을 이용해서 Redis를 사용하는 방법을 알아보자

Redis Client를 사용하기 위해서는 먼저, Redis를 설치해야 한다.
[https://redis.io/docs/install/install-redis/]
에서 OS에 맞는 Redis의 설치를 진행하자

참고로 redis는 windows os를 지원하지 않기에 windows에서 사용하기 위해서는 WSL이나 Docker를 활용하여야 한다.

Jedis를 이용한 방식

먼저 redis dependency를 설정한다.

implementation 'redis.clients:jedis:3.9.0'
implementation ('org.springframework.boot:spring-boot-starter-data-redis'){
        exclude group: 'io.lettuce', module: 'lettuce-core'
}

또한 application.propertiesapplication.yml에 db 연결 설정을 한다.

spring:
    redis:
        host: 127.0.0.1
        port: 6379

기본적인 Redis Configuration은 다음과 같다.

@Configuration
class RedisStandaloneConfiguration {
  @Bean
  public RedisConnectionFactory jedisConnectionFactory() {
    return new JedisConnectionFactory(new RedisStandaloneConfiguration("server", 6379));
  }
  
  @Bean
  public RedisTemplate<?, ?> redisTemplate(){
    RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(jedisConnectionFactory());
    return redisTemplate;
  }
}

이를 앞서 지정한 host와 port 정보를 가져오도록 수정하고 Connection Pool의 설정을 추가하면 다음과 같다.

@Configuration
@RequiredArgsConstructor
@EnableRedisRepositories
public class RedisRepositoryConfig {
    // spring.redis에 설정한 property를 가져옴
    private final RedisProperties redisProperties;

    // Redis를 사용하기 위해 redisTemplate을 설정
    @Bean
    public RedisTemplate<?, ?> redisTemplate(){
        RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }

    // property에서 host, port 정보를 가져와 Jedis Pool Configuration과 함께
    // Jedis Connection Factory Bean을 설정
    @Bean
    public RedisConnectionFactory redisConnectionFactory(){
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(new RedisStandaloneConfiguration(redisProperties.getHost(), redisProperties.getPort()));
        jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
        return jedisConnectionFactory;
    }

    // Jedis Connection Pool의 configuration
    private JedisPoolConfig jedisPoolConfig() {
        final JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(128);
        jedisPoolConfig.setMaxIdle(128);
        jedisPoolConfig.setMinIdle(36);
        jedisPoolConfig.setTestOnBorrow(true);
        jedisPoolConfig.setTestOnReturn(true);
        jedisPoolConfig.setTestWhileIdle(true);
        jedisPoolConfig.setMinEvictableIdleTime(Duration.ofSeconds(60));
        jedisPoolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(30));
        jedisPoolConfig.setNumTestsPerEvictionRun(3);
        jedisPoolConfig.setBlockWhenExhausted(true);
        return jedisPoolConfig;
    }
}

RedisTemplate을 이용하여 사용하는 방법은 아래와 같다.

위에서 RedisTemplate에 ConnectionPool 설정을 주입했기에
RedisTemplate는 Jedis Connection Pool을 이용하여 동작한다.

...
	@Autowired
    private final RedisTemplate redisTemplate;
    
    redisTemplate.opsForValue().set("foo", "bar")
    System.out.println(redisTemplate.opsForValue().get("foo"))
    // prints bar
...

RedisTemplate 대신 JedisPool을 이용하고 싶다면 다음과 같이 사용하면 된다.

	JedisPool pool = new JedisPool("localhost", 6379);

    try (Jedis jedis = pool.getResource()) {            
        jedis.set("foo", "bar");
        System.out.println(jedis.get("foo"));
        // prints bar        
    }

Lettuce를 이용한 방식

먼저 redis dependency를 설정한다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

또한 application.propertiesapplication.yml에 db 연결 설정을 한다.

spring:
    redis:
        host: 127.0.0.1
        port: 6379

Lettuce의 경우 autoConfiguration을 통해
redisTemplateredisConnectionFactory Bean 설정이 제공된다.

따라서 별도의 설정이 필요한 경우에만 Redis Configuration을 작성한다.
ex) default serialization 말고 다른 방식을 사용하고 싶은 경우
JdkSerializationRedisSerializer -> StringRedisSerializer

@Bean
public RedisTemplate<?, ?> redisTemplate(){
    RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redisConnectionFactory());
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(new StringRedisSerializer());
    return redisTemplate;
}

Auto Configuration을 통해 다음과 같은 redisTemplate이 제공되므로
직접 override하지 않고 다른 직렬화 방법을 사용한 Bean을 사용해도 된다.
하지만 직렬화 방법이 다르므로 혼용을 해서는 안된다.

@Autowired
RedisTemplate redisTemplate;

@Autowired
StringRedisTemplate stringRedisTemplate;

@Autowired
ReactiveRedisTemplate reactiveRedisTemplate;

@Autowired
ReactiveStringRedisTemplate reactiveStringRedisTemplate;

이렇게 설정을 마무리했다면 사용 방법은 Jedis와 크게 다르지 않다.

기본으로 제공하는 RedisTemplate를 사용하여 동일하게 사용하면 된다.

	@Autowired
    private final RedisTemplate redisTemplate;
    
    redisTemplate.opsForValue().set("foo", "bar")
    System.out.println(redisTemplate.opsForValue().get("foo"))
    // prints bar

참고

https://redis.io/
https://docs.spring.io/spring-data/redis/reference/redis.html
https://jojoldu.tistory.com/418

profile
Deep dive into development

0개의 댓글