Search
Duplicate
📒

[고성능 서비스를 위한 Redis] 04. 캐시 레이어 만들기

상태
완료
수업
고성능 서비스를 위한 Redis
주제
Redis
4 more properties
참고

캐시(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 내의 데이터가 다를 수 있다.