스프링은 조회 결과를 캐시 메모리에 저장해 놓고 다시 똑같은 요청이 온다면 저장해 놓은 조회 결과를 캐시 메모리에서 꺼내 돌려준다. 메소드를 또 실행하지 않고 저장해놓은 조회 결과를 돌려주므로써 조회의 성능을 끌어 올리 수 있다.
스프링 캐시
에 대해 알아본 후 스프링 레디스 캐시
에 대해 알아보자.
스프링부트 의존성을 추가한다.
implementation("org.springframework.boot:spring-boot-starter-cache")
설정 파일을 작성한다.
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("addresses");
}
}
@EnableCaching
어노테이션을 통해 스프링 애플리케이션의 캐시를 활성화 시킨다.@Component
public class SimpleCacheCustomizer
implements CacheManagerCustomizer<ConcurrentMapCacheManager> {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setCacheNames(asList("users", "transactions"));
}
}
스프링부트
를 사용한다면 @EnableCaching
과 함께 클래스 경로에 스타터 패키지가 존재하는 것만으로도 동일한 ConcurrentMapCacheManager가 등록되어 별로의 설정 클래스가 필요 없다.@Cacheable("addresses")
public String getAddress(Customer customer) {...}
@Cacheable
을 통해 메소드의 결과를 캐싱할 수 있다.캐싱된 결과를 저장할 이름
을 명시해주면 된다.@Cacheable({"addresses", "directory"})
public String getAddress(Customer customer) {...}
@CacheEvict(value="addresses", allEntries=true)
public String updateAddress(Customer customer) {...}
allEntries=true
일 경우 모든 캐시가 삭제된다.@CachePut(value="addresses")
public String getAddress(Customer customer) {...}
@Caching(evict = {
@CacheEvict("addresses"),
@CacheEvict(value="directory", key="#customer.name") })
public String getAddress(Customer customer) {...}
@CacheConfig(cacheNames={"addresses"})
public class CustomerDataService {
@Cacheable
public String getAddress(Customer customer) {...}
클래스 레벨
에서 캐시를 설정할 수 있다.@CachePut(value="addresses", condition="#customer.name=='Tom'")
public String getAddress(Customer customer) {...}
@CachePut(value="addresses", unless="#result.length()<64")
public String getAddress(Customer customer) {...}
스프링은 다양한 캐시를 지원하지만 그 중 레디스에 대해 알아보자.
RedisCacheManager
, RedisCacheManagerBuilder
, RedisCacheConfiguration
구현체를 통해 이루어진다.RedisCacheManager
캐시별로 사용자 정의 구성을 허용한다. 캐시가 2개라면 manager도 2개RedisCacheConfiguration
을 통해 만료시간, prefix, RedisSerializer를 설정할 수 있다.starter-data-redis
를 사용하면 RedisCacheManager
가 기본 캐시 매니저로 자동 등록된다.RedisCacheManager cacheMangager = RedisCacheManager
.build(RedisCacheWriter.lockingRedisCacheWriter(connectionFactory))
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig())
...
RedisCacheWriter.lockingRedisCacheWriter()
를 통해 설정할 수 있다.// static key prefix
RedisCacheConfiguration.defaultCacheConfig().prefixCacheNameWith("(͡° ᴥ ͡°)");
The following example shows how to set a computed prefix:
// computed key prefix
RedisCacheConfiguration.defaultCacheConfig()
.computePrefixWith(cacheName -> "¯\_(ツ)_/¯" + cacheName);
KEYS
와 DEL
명령어를 사용한다.KEYS
명령어는 지정된 패턴의 모든 키를 한번에 반환하므로 키가 많을 때 성능이슈가 있다.RedisCacheManager cacheManager = RedisCacheManager
.build(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory, BatchStrategies.scan(1000)))
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig())
...
BatchStrategy
를 SCAN-based batch strategy
로 바꾸어 RedisCacheWriter를 생성할 수 있다.SCAN
명령어는 키를 반복적으로 스캔하면서 일치하는 키를 반환한다.SCAN 전략
은 배치 사이즈를 필요로한다. 위의 소스에서는 1000개 기준으로 가져온다.time-to-live (TTL)과 time-to-idle (TTI)의 차이점을 알아보자.
스프링 레디스 캐시는 TTL만 지원하고 있다. TTI처럼 동작하기 위해서는 개발자가 로직을 작성해 주어야한다.
RedisCacheConfiguration fiveMinuteTtlExpirationDefaults =
RedisCacheConfiguration.defaultCacheConfig().enableTtl(Duration.ofMinutes(5));
enum MyCustomTtlFunction implements TtlFunction {
INSTANCE;
@Override
public Duration getTimeToLive(Object key, @Nullable Object value) {
// compute a TTL expiration timeout (Duration) based on the cache entry key and/or value
}
}
RedisCacheConfiguration defaults = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(MyCustomTtlFunction.INSTANCE);
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(defaults)
.build();
bealdung cache tutorial
spring cache guide
spring redis cache