본문 바로가기

Spring/Springboot

[Springboot] Redis를 In-memory DB로 사용하기(1)

 

1. ReidsRepository와 RedisTemplate

Spring Data Redis에서 Redis와 상호작용하는데 사용되는 컴포넌트 ReidsRepository와 RedisTemplate

 

1) RedisRepository

  • 역할:
    • RedisRepository는 Spring Data 프로젝트에서 제공하는 일종의 Repository 인터페이스로, Redis에 대한 데이터 액세스를 추상화
    • 사용자가 Redis와 상호 작용하는데 필요한 CRUD (Create, Read, Update, Delete) 기능 제공
  • 주요 특징:
    • 사용자가 정의한 인터페이스를 생성하여 해당 인터페이스에 메소드를 추가함으로써 사용자 지정 Repository를 만들 수 있음
    • Spring Data Redis가 제공하는 일반적인 메소드들로 데이터 저장소에서 데이터를 가져오거나 저장할 수 있음
    • 주로 쿼리 메소드를 정의하여 데이터베이스에 대한 검색 지원
  • 예제
import org.springframework.data.repository.CrudRepository;
import java.util.List;

public interface PersonRepository extends CrudRepository<Person, String> {
    List<Person> findByLastName(String lastName);
}

 

2) RedisTemplate

  • 역할:
    • RedisTemplate은 Redis와 상호 작용하는 데 사용되는 Spring의 핵심 클래스 중 하나
    • 더 저수준의 Redis 명령을 사용하여 데이터를 저장, 조회 및 조작할 수 있음
  • 주요 특징:
    • RedisTemplate은 Redis에 데이터를 저장하고 검색하는 다양한 메소드 제공
    • 직접 Redis 명령어를 실행하거나 데이터를 다양한 데이터 형식으로 변환 가능
    • 더 유연한 사용이 가능하며, 특별한 케이스나 고급 기능을 위해 더 많은 커스터마이징이 가능
  • 예제
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.util.concurrent.TimeUnit;

public class RedisService {
    private final RedisTemplate<String, Object> redisTemplate;

    public RedisService(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public void setValue(String key, Object value) {
        ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();
        valueOps.set(key, value);
        // 설정된 키의 만료 시간을 설정 (예: 10분)
        redisTemplate.expire(key, 10, TimeUnit.MINUTES);
    }

    public Object getValue(String key) {
        ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();
        return valueOps.get(key);
    }
}

 

 

RedisRepository를 먼저 고려하여 간단한 케이스에서 빠르게 작업을 진행하고, 더 복잡한 경우에는 RedisTemplate을 사용하여 필요한 조작을 수행하는 것이 일반적

Redis는 기본적으로 트랜잭션 지원을 하지만 ReidsRepository는 트랜잭션 관련 제어를 지원하는 메서드를 제공하지 않는다고함 -> RedisRepository는 트랜잭션 제어불가

RestTemplate를 사용해서 Redis 사용하기로 결정

 

트랜잭션을 제어하지 않으면 발생하는 문제점

더보기
  1. 원자성 보장의 부재:
    • 트랜잭션을 사용하지 않으면 여러 Redis 명령이 실행될 때 각 명령이 개별적으로 실행되기 때문에, 명령 중 하나가 실패하면 다른 명령이 이미 적용되어 데이터의 일관성이 깨질 수 있습니다.
  2. 데이터 일관성 문제:
    • 여러 명령이 동시에 실행되거나 중간에 오류가 발생할 경우, 데이터 일관성이 유지되지 않을 수 있습니다.
    • 예를 들어, 잔고를 변경하고 해당 잔고를 기록하는 두 가지 작업이 있다고 가정해보면, 첫 번째 작업이 성공하고 두 번째 작업이 실패하면 실제 잔고와 기록된 잔고가 일치하지 않을 수 있습니다.
  3. 예외 발생 시 롤백 불가능:
    • 트랜잭션을 사용하지 않으면 명령을 실행하는 도중 예외가 발생하면 해당 명령은 이미 적용된 상태가 됩니다.
    • 따라서 예외가 발생하면 롤백이 불가능하며, 일부 명령은 이미 실행되었을 수 있습니다.
  4. 동시성 제어 부재:
    • 여러 클라이언트가 동시에 데이터를 수정하면 데이터 일관성 문제가 발생할 수 있습니다.
    • 트랜잭션을 사용하지 않으면 동시에 여러 클라이언트가 동일한 데이터를 수정할 때 예측할 수 없는 결과가 발생할 수 있습니다.
  5. 복잡한 로직의 처리 어려움:
    • 복잡한 비즈니스 로직을 구현하고 특정 상태에서 롤백이 필요한 경우, 트랜잭션을 사용하지 않으면 해당 로직의 일부만 실행되었을 때 롤백하기가 어려울 수 있습니다.

따라서 트랜잭션은 여러 명령을 논리적 단위로 묶어서 실행하고, 성공할 경우에만 모든 변경 사항을 적용하는 중요한 도구입니다. 특히 데이터 일관성과 동시성 제어를 보장하는데 중요한 역할을 합니다.

 

 

 

 

2. Java에서 Redis와 상호작용하기 위한 클라이언트 라이브러리 Jedis 와 Lettuce

 

1) Jedis

  1. 동기 (Synchronous):
    • Jedis는 동기 방식으로 동작, Redis 명령을 보내고 결과를 기다리는 동안 블록(block)됨
    • 멀티스레드 환경에서 동시성 처리에 주의 필요
  2. 쓰레드 안전성:
    • 멀티스레드 환경에서는 단일 인스턴스를 여러 쓰레드가 공유하기 어려우며, 일반적으로 각 쓰레드에 대해 별도의 Jedis 인스턴스를 사용하는 것이 권장됨
  3. Connection Pooling:
    • Jedis는 내장된 커넥션 풀을 제공하지만, 사용자는 쉽게 커넥션 풀을 설정하고 관리하기가 어려움

 

2) Lettuce

  1. 비동기 (Asynchronous):
    • 비동기 방식으로 동작, Redis 명령을 비동기적으로 보내고, 결과를 기다리지 않고 콜백을 통해 처리할 수 있음
    • 비동기 방식은 더 뛰어난 확장성과 성능을 제공할 수 있음
  2. 쓰레드 안전성:
    • 스레드 안전하게 설계되어 여러 스레드가 동시에 하나의 StatefulConnection을 공유할 수 있음
  3. Connection Pooling:
    • 유연하고 강력한 커넥션 풀링 기능을 제공
    • 커넥션 풀을 세밀하게 조절하고 다양한 환경에서 효율적으로 사용할 수 있음
  4. Redis Sentinel 및 Redis Cluster 지원:
    • Redis Sentinel 및 Redis Cluster를 지원
  5. Reactive API:
    •  Reactive 프로그래밍 모델을 지원하는 Reactive API를 제공
  6. 가변적인 연결:
    • 연결이 유실되면 새로운 연결을 생성하고 자동으로 다시 연결하는 등의 유연한 연결 관리 지원

 

3) 결론

  • 성능과 확장성:
    • 대규모 또는 성능 중심의 환경에서는 Lettuce가 더 적합할 수 있음
  • 간편한 사용:
    • 단일 쓰레드 환경이거나 간단한 사용 사례에서는 Jedis가 더 간편할 수 있음
  • 비동기 및 Reactive 프로그래밍:
    • 비동기 또는 Reactive 프로그래밍을 선호한다면 Lettuce 
  • 고급 기능 및 설정:
    • Lettuce는 더 많은 고급 기능과 커스터마이징 옵션 제공

 

일반적으로는 Lettuce가 더 최신이며 확장성이 뛰어나기 때문에, 새로운 프로젝트에서는 Lettuce를 고려하는 것이 좋지만 기존에 Jedis를 사용 중이고 문제가 없다면 변경할 필요는 없다고 함

 

다중 스레드 환경이며, 성능 중심 환경에서 Lettuce가 더 적합할 수 있다고 하여 Lettuce 사용 선택