코프링에서 Redis 캐시 사용하기

h블로그·2022년 10월 7일

redis

목록 보기
1/3

조회 성능을 위해서 cache를 써야한다
먼저 로컬에서 레디스 구동시켜서 연동을 확인하려고 한다

환경

  • macos m1
  • intellij
  • spring boot
  • kotlin

redis 설치

docker 다운

// 이미지 다운 
docker pull redis
// 이미지 확인
docker images

// 컨테이너 올림
docker run --name test-redis -p 6379:6379 -d redis
// 올라간 컨테이너 확인
docker ps 

java client

  • Jedis
  • Lettuce
    두가지가 있는데, 예전엔 Jedis가 주로 쓰였으나, Lettuce 가 요즘엔 더 많이 쓰이며 spring boot2.0 부터는 내장되었다고 한다
    그래서 나도 Lettuce!

Spring boot 에 redis 설정

의존성 주입

implementation("org.springframework.boot:spring-boot-starter-data-redis")
// mac silicon only
val isMacOS: Boolean = System.getProperty("os.name").startsWith("Mac OS X")
val architecture = System.getProperty("os.arch").toLowerCase()
if (isMacOS && architecture == "aarch64") {
    developmentOnly("io.netty:netty-resolver-dns-native-macos:4.1.68.Final:osx-aarch_64")

spring-boot-starter-data-redis 만 주입하고 실행했더니, 실행은 되지만 중간에 에러 로그들이 쌓였다.
찾아보니까, m1 인 경우에만 발생하는 로그들이였다.
(m1이 아니라면 아래 라인 의존성은 하지 않아도 된다.)
다른 글을 참고해서 io.netty:netty-resolver-dns-native-macos:4.1.82.Final:osx-aarch_64 을 m1 개발환경에서만 실행되게 했다. 참고한 글에 의하면 의존성이 포함되어있어도 배포시에는 문제가 없다고 한다.

참고
https://junho85.pe.kr/2054
https://github.com/netty/netty/issues/11020#issuecomment-1193280582

application.yml

spring 
  redis
    host: localhost
    port: 6379

RedisCacheConfig

@Configuration
@EnableCaching
class RedisCacheConfig(
    @Value("\${spring.redis.host}")
    private val host: String,
    @Value("\${spring.redis.port}")
    private val port: Int
) {

    @Bean
    fun redisConnectionFactory(): RedisConnectionFactory = LettuceConnectionFactory(host, port)

    @Bean
    fun cacheManager(): CacheManager {
        val objectMapper = ObjectMapper()
            .registerModule(JavaTimeModule())
            .activateDefaultTyping(BasicPolymorphicTypeValidator.builder()
                .allowIfBaseType(Any::class.java).build(), ObjectMapper.DefaultTyping.EVERYTHING)

        val redisCacheConfiguration: RedisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair
                .fromSerializer(GenericJackson2JsonRedisSerializer(objectMapper)))
            .entryTtl(Duration.ofMinutes(3L))

        return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory())
            .cacheDefaults(redisCacheConfiguration).build()
    }
}
  • LettuceConnectionFactory Bean 등록
  • ttl 지속 시간은 3분으로 지정

serialize 설정

cacheManager 에 serialize 설정을 원래는 다른 글들을 보고 아래처럼 했었다.

.serializeValuesWith(RedisSerializationContext.SerializationPair
                .fromSerializer(GenericJackson2JsonRedisSerializer()))

GenericJackson2JsonRedisSerializer 을 쓰게되면 @class 라는 프로퍼티가 redis 에 같이 적재된다고 했는데, 나는 없어서 자꾸 에러가 나는 것이다.

error log
Exception while fetching data (/findNoticeOne) : Could not read JSON: Could not resolve subtype of [simple type, class java.lang.Object]: missing type id property '@class' at

혹시 kotlin 이라서 그럴까..? 하고 구글링 해보니, 레퍼런스가 나왔다.

https://stackoverflow.com/questions/52265326/how-can-i-easily-cache-kotlin-objects-in-redis-using-json-via-jackson

정확한 원인은 모르겠으나, kotlin의 serialze가 다른 부분이 있는 것 같다.

@cacheable

aop annotation으로 결과가 redis 에 캐싱되는걸 테스트 해봤다
원래 만들어둔 graphql method 에 아래 어노테이션을 사용했고, 같은 조회 쿼리를 2번 날렸을때 2번째에는 쿼리가 찍히지 않는 것을 확인했다 !!

@Cacheable(key = "#id", value = ["notice"])

redis-cli 통해서 데이터도 확인했는데, 불편하긴 하더라.
기능 구현할때 적절한 어노테이션을 사용해서 해봐야지.

profile
😎🙈🙈🙈🤓

0개의 댓글