[Redis] Spring Boot와 Redis 연동

YuLim·2023년 4월 24일
1

부트캠프 메인 프로젝트에서 사용한 Redis를 정리해보려고 합니다.

💻 Redis

Redis는 In-memory 기반의 NoSQL DBMS로서 Key-Value의 구조를 가지고있다. 또한 속도가 빠르고 사용이 간편하다.
보통 캐싱 / 세션관리 등으로 쓰지만 부트캠프 메인 브로젝트에서 임시데이터를 잠시 저장하고 그걸 빠르게 가져오기 위해 사용했다.


💻 Redis Client : Jedis와 Lettuce

redis는 connectionFactory로 Lettuce와 Jedis 두 가지를 제공한다.
default로 Lettuce를 제공하고 Jedis는 Deprecated된다고 한다.
성능적인 면에서도 Lettuce가 좋다고 해서 Lettuce를 사용했다.


💻 Spring Data Redis 라이브러리

Spring Boot에서 Redis를 사용하려면 Spring Data Redis 라이브러리가 필요하다.
Spring Data Redis 라이브러리는 2가지 방식을 제공한다.

  • RedisTemplate
  • RedisRepository

메인 프로젝트에선 RedisTemplate 방식을 사용했다.


✔ build.gradle 의존성 추가

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

✔ .yml 설정

application.ymlhostport를 설정한다.

spring:
  redis:
    host: localhost
    port: 6379

Redis의 localhost:6379는 기본값이다.


💻 Redis Configuraiton

@Configuration
@EnableRedisRepositories
public class RedisConfiguration {

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

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

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

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

✔ RedisConnectionFactory

redisConnectionFactory()를 통해 Lettuce로 Redis와 연결한다.
RedisStandaloneConfiguration 객체를 통해 redis 접속 정보(host, port 등)를 갖고 있는 객체를 생성한다.
RedisStandaloneConfiguration은 single node에 redis를 연결하기 위한 설정 정보를 가지고 있는 기본 클래스이다.
redis 설정 정보가 담긴 RedisStandaloneConfigurationLettuceConnectionFactory에 담아서 반환한다.

✔ RedisTemplate

Spring Boot 2.0부터 RedisTemplateStringTemplate 두 가지 Bean을 자동으로 생성하여 제공하고 있다고 한다.
RedisTemplate에는 serializer를 설정해주는데 설정하지 않는 다면 스프링에서 조회할 때는 값이 정상으로 보이지만 redis-cli로 데이터 확인이 어렵다.
따라서 개별 설정을 하고자 하는 경우 그냥 해당 Bean을 별도로 생성하면 된다.

@Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());

        // 기본적인 key:value의 경우 시리얼라이저
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());

        // Hash를 사용할 경우 시리얼라이저
        // redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        // redisTemplate.setHashValueSerializer(new StringRedisSerializer());

        // 모든 경우
        // redisTemplate.setDefaultSerializer(new StringRedisSerializer());

        return redisTemplate;
    }

StringRedisSerializer

redis에 객체를 저장할 때 redis-cli로 확인해 보면 byte코드로 저장되어 serializer를 통해 직렬화해 주어야 한다.
다양한 직렬화 방법 중 StringRedisSerializer를 사용했다.
String 값을 그대로 저장하는 Serializer이다. 따라서 객체를 Json형태로 변환하여 Redis에 저장하기 위해서는 직접 Encoding, Decoding을 해주어야 한다는 단점이 존재한다.
이때 StringRedisSerializer를 사용하고 직접 Json Parser를 적용하는 방식으로 RedisTemplate을 사용하여 단점을 보완한다.


💻 RedisService

@Service
@Slf4j
@RequiredArgsConstructor
public class RedisService {
    private final RedisTemplate<String, String> redisTemplate;
    private final JwtTokenizer jwtTokenizer;

    // key-value = RefrshToken-Email
    public void setRefreshToken(String refreshToken, String email, long expirationMinutes) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();

        // 만료시간 이후 삭제
        valueOperations.set(refreshToken, email, Duration.ofMinutes(expirationMinutes));
        log.info("만료 시간, 분: {}", Duration.ofMinutes(expirationMinutes));
    }

    // AccessToken 로그아웃
    public void setAccessTokenLogout(String accessToken, long expiration) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        valueOperations.set(accessToken, "logout", expiration, TimeUnit.MILLISECONDS);
        String expireFormatString = String.format("%d min, %d sec",
                TimeUnit.MILLISECONDS.toMinutes(expiration),
                TimeUnit.MILLISECONDS.toSeconds(expiration) -
                        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(expiration))
        );
        log.info("access token 만료 시간, {}", expireFormatString);
    }


    // get RefreshToken
    public String getRefreshToken(String refreshToken) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        // RefreshToken 없으면 null 반환
        return valueOperations.get(refreshToken);
    }

    // get AccessToken
    public String getAccessToken(String accessToken) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        return valueOperations.get(accessToken);
    }

    // delete RefreshToken
    public void deleteRefreshToken(String refreshToken) {
        // delete 메서드 삭제 시 true 반환
        redisTemplate.delete(refreshToken);
    }
}

✔ Redis Method

Redis는 자료구조에 따라 사용하는 메서드가 다르다.

  • 메서드 명 | 반환 타입(오퍼레이션) | Redis 자료구조
  • opsForValue | ValueOperations | String
  • opsForList | ListOperations | List
  • opsForSet | SetOperations | Set
  • opsForZSet | ZSetOperations | Sorted Set
  • opsForHash | HashOperations | Hash

Duration (지속, (지속되는)기간)

Duration을 설정해주어 메모리에서 데이터가 증발하는 시간을 정해준다.

TimeUnit

데이터를 저장할 때 만료 시간 지정할 시에는 해당 시간의 단위까지 지정해주면 된다. RedisService.java에서는 TimeUnit.MILLISECONDS(밀리 초)로 적용되어 있다.

Method

  • redisTemplate.opsForValue().get(key) : key 값으로 value 를 가져온다.
    • Redis DB 에서 값을 가져올 때는 valueOperations.get(key) 의 구조로 가져오게 되고, 데이터 조회를 하여 값이 없는 경우 null 을 가져온다. 이때 StringUtils.isBlank(valueOp.get(key)) 형식으로 가져오는 것이 안전한 방법이다.
  • redisTemplate.opsForValue().set(key, value, time, unit) : key값으로 value를 저장한다 만약 만료 시간을 지정하는 경우엔 time 과 단위를 함께 세팅한다.
  • redisTemplate.hasKey(key) : 키의 존재유무를 return 한다.
  • redisTemplate.delete(key) : key값에 대한 데이터를 삭제한다.

version

java 11
Spring Boot 2.7.9
Gradle 7.6.1

❗ 틀린 부분 댓글 첨언 환영합니다 ❗

profile
개인 공부 기록장

0개의 댓글