티스토리 뷰

 

 

 

이전 글에서 자세히 다루지 못 했던 Redis Configuration을 뜯어보려고 한다.

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

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

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
        redisConfiguration.setHostName(host);
        redisConfiguration.setPort(port);
        return new LettuceConnectionFactory(redisConfiguration);
    }

    @Primary
    @Bean
    public RedisTemplate<String, String> redisTemplate() {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

 

RedisConnectionFactory이란?

 

RedisConnectionFactory는 Redis 데이터베이스와의 연결을 설정하는 역할이다.

Redis 서버와의 연결을 만들고 관리를 담당하며,

Spring Data Redis에서는 LettuceConnectionFactory와 JedisConnectionFactory가 가장 일반적으로 사용된다.

 

Lettuce vs Jedis

참고 URL : https://redis.com/blog/jedis-vs-lettuce-an-exploration/

 

위는 Redis 공식 사이트에서 Lettuce와 Jedis를 설명한 글 중 Lettuce의 일부를 캡쳐한 내용이다.

Lettuce는 비동기(동기도 지원함) 및 리액티브 프로그래밍을 지원하여 더 뛰어난 성능과 확장성을 제공한다고 한다.

 

스프링부트에서는 LettuceConnectionFactory를 이용해 Lettuce 라이브러리를 기반으로 Redis와 연결한다. 

public class LettuceSetGet {
 
    private static final String YOUR_CONNECTION_STRING = "redis://:foobared@yourserver:6379/0";
 
    public static void main(String[] args) {
        RedisClient redisClient = RedisClient.create(YOUR_CONNECTION_STRING);
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        RedisCommands<String, String> sync = connection.sync();
 
        sync.set("foo", "bar");
 
        String result = sync.get("foo");
 
        connection.close();
        redisClient.shutdown();
 
        System.out.println(result); // "bar"
    }
}

얼핏 보기에 상당히 단순 연결을 수행하는데만 해도 복잡하다고 느껴진다. 

 

이렇게 복잡한 이유는 connection이 비동기 기능을 지원하기 때문이다.

 

비동기를 구현한 코드를 보면, 처음 단일 연결 할 때 주어진 커넥션으로 비동기적인 부분을 해결할 수 있다.

public class LettuceAsync {
 
    private static final String YOUR_CONNECTION_STRING = "redis://:foobared@yourserver:6379/0";
 
    public static void main(String[] args) {
        RedisClient redisClient = RedisClient.create(YOUR_CONNECTION_STRING);
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        RedisAsyncCommands<String, String> async = connection.async();
 
        final String[] result = new String[1];
 
        async.set("foo", "bar")
                .thenComposeAsync(ok -> async.get("foo"))
                .thenAccept(s -> result[0] = s)
                .toCompletableFuture()
                .join();
 
        connection.close();
        redisClient.shutdown();
 
        System.out.println(result[0]); // "bar"
    }
}

 

위 역시 Redis 공식 사이트에서 발췌한 글이다.

 

더 적은 기능을 제공하지만 더 쉽게 Redis 클러스터와의 연결을 지원한다고 한다.

public class JedisSetGet {
 
    private static final String YOUR_CONNECTION_STRING = "redis://:foobared@yourserver:6379/0";
 
    public static void main(String[] args) {
 
        Jedis jedis = new Jedis(YOUR_CONNECTION_STRING);
 
        jedis.set("foo", "bar");
        String result = jedis.get("foo");
 
        jedis.close();
 
        System.out.println(result); // "bar"
    }
}

코드를 보면 확실히 Lettuce보다 쉽고 직관적이다.


위와 코드와 같이 Jedis는 쉬운 사용성이 장점이지만, 동기적으로 동작한다는 한계가 있다.

 

비동기적인 부분을 지원하긴 한다. JedisPool을 이용해 멀티쓰레드 환경에서 동작하도록 할 수 있다.

public class JedisMultithreaded {
 
    private static final String YOUR_CONNECTION_STRING = "redis://:foobared@yourserver:6379/0";
 
    public static void main(String[] args) {
        JedisPool pool = new JedisPool(YOUR_CONNECTION_STRING);
 
        List<String> allResults = IntStream.rangeClosed(1, 5)
                .parallel()
                .mapToObj(n -> {
                    Jedis jedis = pool.getResource();
 
                    jedis.set("foo" + n, "bar" + n);
                    String result = jedis.get("foo" + n);
 
                    jedis.close();
 
                    return result;
                })
                .collect(Collectors.toList());
 
        pool.close();
 
        System.out.println(allResults); // "bar1, bar2, bar3, bar4, bar5"
    }
}

하지만, Jedis가 동기적으로 동작한다는 부분에는 변함이 없어

 

모든 풀이 사용 중일 경우 요청과 응답 사이에 블로킹이 발생해 어느정도의 유휴상태에 빠질 수 있다고 한다.

 

그래서 뭘 쓸꺼야?

위 참고 URL을 쭉 읽어보면, "상황에 따라" 결정하라고하며 어떤게 더 좋다고 결정짓지는 않았다. 

 

하지만 동기적 연결만 지원한다는 건 극단적인 환경(트래픽이 몰리는 상황)에서 병목을 발생시키는 등 한계를 보일 수 있는 문제라 생각이 든다. 

 

또한 Jedis는 Redis의 클러스터 모드를 지원하지 않는다고 한다.

 

그래서인지 최신 버전의 Spring Data Redis에서는 비동기 및 리액티브 프로그래밍을 지원하는

 

Lettuce를 사용한 LettuceConnectionFactory가 권장된다고 한다.

 

RedisTemplate이란?

설정만하고 직접사용하지 않기 때문에 글로만 짧게 정리하고 넘어간다.

 

RedisTemplate는 Redis 데이터베이스와 상호작용하기 위한 설정을 담은 클래스이다.


이 클래스는 Redis 연결을 통해 데이터를 저장하고 검색하기 위한 다양한 메서드를 제공한다.

 

RedisTemplate을 이용해 직접 Redis와 연결 후 CRUD를 실행 할 수도 있지만


Spring Data의 CrudRepository를 이용하면 더 간단하게 사용할 수 있기 때문에 직접 사용하는 경우는 드물다.

 

마치며

별 생각없이 Lettuce를 쓰고 있었는데, 다른 개발자분이 GPT한테 물어보니 Jedis를 썼다고 해서 이 내용을 조금 더 알아봤다.

 

Configuration부분은 늘 숨겨져 있어 자세히 알기 힘들었던 부분 같다.

 

아는만큼 보인다는걸 다시한번 느꼈다.

'개발 > Redis' 카테고리의 다른 글

Windows 환경에서 스프링부트 + Redis 사용하기  (0) 2023.08.02
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함