이전 포스팅에서 Redis의 사용 방법을 알아봤습니다. 이번에는 Redis로 Cache를 사용해보겠습니다. 

 

Local Memory Cache는 Memory가 초기화된다면 데이터가 다 삭제되지만, Redis는 expires를 설정하거나 직접 삭제하지 않는 이상 데이터는 삭제되지 않습니다. 따라서 스냅숏 같이 개발자의 원하는 시점의 데이터를 불러와 Cache로 저장할 수 있습니다. 

1. Redis CacheManager

SimpleCacheManager를 사용하지 않고, Redis의 CacheManager를 정의하여 사용합니다.

@Bean
public CacheManager redisCacheManager(){
    RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
            .entryTtl(Duration.ofSeconds(10));
    RedisCacheManager cacheManager = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory())
            .cacheDefaults(redisCacheConfiguration).build();

    return cacheManager;
}

RedisCacheConfiguration을 생성하고 설정을 부여합니다.

1. 키: 직렬화

2. Value: Object를 직렬화 

3. entryTtl: Cache 유지 시간을 의미합니다. (예제는 10초로 설정했습니다.)

4. 이전에 생성한 LettuceConnectionFactory를 주입하고, RedisCacheManager를 생성합니다.  

2. RedisCacheMemberService

Local Memory Cache를 이용한 것처럼

@Cache관련 어노테이션을 똑같이 사용해줍니다. 

package com.example.cache.service;

import com.example.cache.domain.Dto;
import com.example.cache.domain.RedisMember;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.annotations.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
@RequiredArgsConstructor
@Slf4j
public class RedisCacheMemberService {

    private final RedisTemplate<String, RedisMember> redisTemplate;

    @Cacheable(value = "redisMemberOne",key = "#id")
    public Dto findOne(String id){
        log.info("findOne implement!!");
        RedisMember redisMember = redisTemplate.opsForValue().get(id);
        return new Dto(redisMember.getName(),redisMember.getAge(),"noCity");
    }

    @CacheEvict(value = "redisMemberOne", key = "#id")
    public void deleteMember(String id){
        redisTemplate.delete(id);
    }

    @CachePut(value = "redisMemberOne",key = "#id")
    public Dto changeAge(int age, String id){
        log.info("changeAge implement!!");
        RedisMember redisMember = redisTemplate.opsForValue().get(id);
        redisMember.changeAge(age);
        redisTemplate.opsForValue().set(id,redisMember);
        return new Dto(redisMember.getName(),redisMember.getAge(),"noCity");
    }
}

1. findOne: 아이디를 key로 찾습니다.

2. deleteMember: 아이디를 기반으로 redis에서 삭제하고, redisMemberOne에서의 값을 삭제합니다.

3. changeAge: 아이디를 기반으로 나이를 변경하고, @CachePut 어노테이션이 있으므로 Cache가 업데이트 됩니다. 

3. 더미 데이터 생성

application에 @PostConstruct를 이용해서 더미 데이터를 생성해줍니다.

@PostConstruct
public void init(){
    for(int i=0; i<10; i++){
        RedisMember redisMember = new RedisMember("m" + i, i);
        redisTemplate.opsForValue().set(redisMember.getId(),redisMember);
    }
}

4. RedisCacheMemberController

전보다 추가된 개념이 없는 controller이므로 설명은 생략하겠습니다.

@RestController
@RequiredArgsConstructor
@RequestMapping("/redis")
public class RedisCacheMemberController {

    private final RedisCacheMemberService memberService;


    @GetMapping("/members/{id}")
    public Dto findOne(@PathVariable String id){
        return memberService.findOne(id);
    }

    @DeleteMapping("/members/{id}")
    public String deleteMember(@PathVariable String id){
        memberService.deleteMember(id);
        return "ok";
    }

    @PatchMapping("/members/{id}")
    public Dto changeAge(@PathVariable String id, @RequestParam int age){
        return memberService.changeAge(age, id);

    }
}

5. 캐시 테스트

5-1. RedisMember 조회

id가 m1인 RediMember를 조회해보겠습니다.

uri: localhost:8080/redis/members/m1 GET

-> 처음 요청에만 findOne이 실행되고, 그다음부터는 Cache에서 불러오므로 findOne의 log가 찍히지 않는 것을 알 수 있습니다.

단 cache 유지 시간을 10초로 해놨으므로 10초 뒤에는 cache가 없어져서 findOne이 실행됩니다.

5-2. RedisMember age 변경 후 조회하기

나이를 변경하고, 조회하겠습니다.

uri: localhost:8080/redis/members/m1? age=10 PATCH

 

변경 후 조회

 

변경된 나이로 cache가 조회된 것을 확인할 수 있습니다. 

Local Memory Cache처럼 @CacheEvict도 사용할 수 있습니다. (생략하겠습니다.)

 

 

지금까지 Redis로 Cache를 사용해봤습니다. 다음은 Redis 캐시 서버의 Master와 slave를 적용해보겠습니다. 감사합니다. 

 

모든 코드는 아래 링크에서 확인 가능합니다.

https://github.com/rlaehdals/springbootCache

 

GitHub - rlaehdals/springbootCache

Contribute to rlaehdals/springbootCache development by creating an account on GitHub.

github.com