참고
캐시(Cache)와 캐싱(Caching)
NOTE
캐시 ⇒데이터의 값을 미리 복사해 놓는 임시 장소를 의미한다!
캐시는 CPU, 서버, 데이터베이스 등 다양한 곳에서 사용된다.
•
캐시 사용을 위해 고려해야하는 부분
◦
별도의 연산 수행이 없어 동일한 응답 값 전달이 가능해야한다.
◦
어떤 기준으로 Cache를 적용할지 결정
◦
Cache의 유지 기간을 고려
•
캐시를 주로 사용하는 경우
◦
Content에 대한 정보조회
◦
즉시 메세지를 주고 받아야하는 경우
◦
장바구니의 삭제
•
캐시 공간은 작으므로, 공간이 모자라게 되면 안 쓰는 데이터부터 삭제하여 공간을 확보한다. (Eviction)
Springboot - Redis 설정
NOTE
spring:
cache:
type: redis
redis:
host: localhost
port: 6379
YAML
복사
어노테이션을 사용하기 위해 설
@Configuration
public class RedisCacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofSeconds(10)) // 기본 TTL
.computePrefixWith(CacheKeyPrefix.simple())
.serializeKeysWith(
RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())
);
HashMap<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("userAgeCache", RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(5))); // 특정 캐시에 대한 TTL
return RedisCacheManager
.RedisCacheManagerBuilder
.fromConnectionFactory(connectionFactory)
.cacheDefaults(configuration)
.withInitialCacheConfigurations(configMap)
.build();
}
}
Java
복사
만료시간 등 Redis의 설정을 만들 수 있음
Springboot - ValueOpertion 사용
NOTE
ValueOperations<String, String> ops = redisTemplate.opsForValue();
String cachedName = ops.get("nameKey: " + userId);
String userName;
if (cachedName != null) {
userName = cachedName;
}
else{
userName = externalApiService.getUserName(userId);
ops.set("nameKey: " + userId, userName, 5, TimeUnit.SECONDS);
}
Java
복사
ValueOperation을 활용한 캐시사용
Springboot - Annotation 사용
NOTE
@Cacheable(cacheNames = "userAgeCache", key = "#userId")
public int getUserAge(String userId) {
Java
복사
Redis에 캐싱된 데이터가 있으면 반환하고 없으면 DB에서 조회한다음 Redis에 캐시한다
이렇게 저장됨
@CachePut(value = CacheKey.USER, key = "#user.msrl")
@PutMapping("/user")
@ResponseBody
public User putUser(@RequestBody User user) {
return userJpaRepo.save(user);
}
Java
복사
Redis에 저장된 캐시정보를 갱신한다 (없으면 생성함)
@CacheEvict(value = CacheKey.USER, key = "#msrl")
@DeleteMapping("/user/{msrl}")
@ResponseBody
public boolean deleteUser(@PathVariable long msrl) {
userJpaRepo.deleteById(msrl);
return true;
}
Java
복사
Redis에 저장된 캐시정보를 삭제한다.
캐싱 전략 턴
NOTE
캐시는 RAM을 사용하기에 DISK와 비교해 용량이 부족하므로 데이터를 얼마나 저장하고 제거하는지에 대한 전략이 필요하다!
Cache가 있다면 hit, 없다면 miss
•
cache hit
◦
캐시 스토어(redis)에 데이터가 있을 경우 바로 가져옴
•
cache miss
◦
캐시 스토어(redis)에 데이터가 없을 경우 어쩔수 없이 DB에서 가져옴
Look Aside 패턴
NOTE
Cache를 먼저 확인하고, 이후 DB를 확인하는 패턴!
•
반복적으로 동일 쿼리를 수행하는 서비스에 적합하다.
•
단건 호출 빈도가 높으면, 별로 적합하지가 않다.
Read Through 패턴
NOTE
캐시에서만 데이터를 읽어오는 전략!
Cache에 없으면 DB에서 읽어오고 Redis에 저장한뒤 반환함
•
데이터 동기화가 항상 이루어져서, 정합성 문제에서 벗어날 수 있다.
•
데이터를 조회하는데 있어 전체적인 속도가 느리다.
Write Through 패턴
NOTE
DB와 Cache에 동시에 데이터를 저장하는 전략!
Cache에 먼저 저장한뒤 바로 DB에 저장한다.
•
캐시와 백업 저장소 업데이트가 동시에 일어나서 데이터 일관성을 유지할 수 있다.
•
데이터 유실이 발생하지 않는다.
•
자주 사용되지 않는 불필요한 리소스가 저장될 수 있다.
•
매 요청마다 2번의 Write가 발생하므로, 수정이 많은경우 성능이슈가 생긴다.
Write Around 패턴
NOTE
Cache를 먼저 확인하고, 이후 DB를 확인하는 패턴!
모든 데이터는 DB에 저장! (캐시 갱신 X)
•
Cache miss가 발생하는 경우에만 DB와 Cache에도 데이터를 저장한다.
•
속도가 빠르다.
•
캐시와 DB 내의 데이터가 다를 수 있다.