[목표]
- 완성날짜 : 7월29일(금)
[현재 진행상태]
- 진행중
- 문서정리 : 60%
💾. CacheCache란?Cache 사용 목적Cache의 대상이 되는 정보예시Cache 주의 사항SpringBoot 공식 지원하는 Third-Party Cache 라이브러리Spring Cache🏷 Cache Abstraction🥸 Cache ManagerConcurrentMapCacheManager📌 의존성 추가EnableCachingCacheableCachePutCacheEvictCachingCacheConfig사용해보기사용 결과1. 조회2. 수정 후 조회💿 RedisRedis 사용 이유Redis 설정 방법🔖 참고 사항
💾. Cache
Cache란?
자주 사용하는 데이터를 저장해서 재활용 하는 기술
- 한번 처리한 데이터를 임시로 저장 → 필요에 따라 전송, 갱신, 삭제하는 기술
보통은 데이터의 보관 장소로 서버의 메모리를 사용하는 경우가 많다.
도서관의 이달의 추천 책 리스트를 예시로 한다면,
집으로 가져갈 복사본이 캐시, 집이라는 근접한 공간이 고속 데이터 스토리지에 해당한다.
- 그래서 디스크에서 정보를 얻어오는 것보다 훨씬 빠르게 I/O 성능을 얻을 수 있지만, 서버가 다운되거나 재부팅되는 경우에는 사라지는 휘발성 성격을 가지기 때문에 임시적으로 보관하고 빠르게 그 정보에 접근하기 위한 용도로 사용해야 한다.
정보의 성격에 따라 디스크 백업 및 TTL 등의 설정으로 영구 보관이나 오랜기간 유지 가능하지만…
이런 설정들이 필요하다면 Cache를 적용하는 것이 맞는지 타당성을 검토해볼 필요가 있다.
Cache 사용 목적
- 서버 간의 불필요한 트래픽을 줄일 수 있다. → 웹 앱 서버의 부하를 감소
- 앱의 빠른 처리 성능(조회)을 확보해서 궁극적으로 앱을 사용하는 클라이언트에게 쾌적한 서비스 경험을 제공하는 것
Cache의 대상이 되는 정보
- 단순한, 또는 단순한 구조의 정보
- 반복적으로 동일하게 제공되는 정보
- 정보의 변경주기가 빈번하지 않고, 단위 처리 시간이 오래 걸리는 정보
- 정보의 최신화가 반드시 실시간으로 이뤄지지 않아도 서비스 품질에 영향을 거의 주지 않는 정보 등등
저 조건들 중에 2개 이상 포함되는 성격의 서비스와 정보라면 Cache를 적용하는 것을 고려 추천!
예시
- 포탈의 검색어
- 쇼핑몰의 핫딜 상품, 베스트 셀러, 추천 상품 등
- 상품의 카테고리와 카테고리별 등록 상품 수
- 방문자 수, 조회 수, 추천 수
- 1회성 인증 정보(SMS 본인인증정보, IP 정보 등)
- 공지사항, Q & A
예시로 우리가 웹사이트에서 보는 대부분의 이미지는 다 캐싱된 이미지 이다.
(CDN의 가장 중요한 기능)
Cache 주의 사항
- 캐싱할 정보 대상
- 캐싱할 정보의 유효기간(TTL - Time To Live)
- 캐싱할 정보의 갱신 시점
서비스 설계 때, 백엔드의 경우 API 서비스의 기능 설계단계부터 Cache 정책을 수립하는게 좋다.
어떤 정보를 Cache로 적용할지를 먼저 검토해보고 그 정보들을 어떤 시점, 어떤 주기로 갱신, 삭제할지에 대한
최소한의 캐싱 전략을 세우는 것도 설계의 중요한 영역중 하나이다.
SpringBoot 공식 지원하는 Third-Party Cache 라이브러리
- Redis
- Caffeine
- EhCache
- Hazelcate
- Infinispan
Guava (SpringBoot 2.0 삭제)
Spring Cache
🏷 Cache Abstraction
스프링 캐시 추상화는 캐시 특정 기술에 종속되지 않으며, AOP를 통해 적용되어
애플리케이션 코드를 수정하지 않고 캐시 부가기능을 추가할 수 있다.
즉, 캐시 API를 코드에 추가하지 않아도 손쉽게 캐시 기능을 부여할 수 있습니다.
또한 캐시 서비스 구현 기술에 종속되지 않도록 추상화 서비스를 제공하기 때문에 환경이 바뀌거나
적용할 기술을 변경해서 캐시 서비스의 종류가 달라지더라도 애플리케이션 코드에 영향을 주지 않습니다.
더 자세히 말하면 캐싱이 필요한 비지니스 로직에서 EhCache, Redis 등 캐싱 종류에 의존하지 않고
추상화된 인터페이스로 캐싱을 적용할 수 있습니다.
🥸 Cache Manager
캐시 추상화에서는 캐시 기술을 지원하는 캐시 매니저를 빈으로 등록해야 한다.
ConcurrentMapCacheManager
…
📌 의존성 추가
- Maven
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> </dependencies>
- Gradle
implementation 'org.springframework.boot:spring-boot-starter-cache:2.7.0'
EnableCaching
Cacheable
적용된 메서드의 리턴값을 기준으로 캐시에 값을 저장한다.
캐시에 데이터가 없을 경우에는 기존의 로직을 실행한 후에 캐시에 데이터 추가,
캐시에 데이터가 있으면 캐시의 데이터를 반환한다.
속성 | 설명 | 타입 |
cacheName | 입력할 캐시 이름 | String[] |
value | cacheNamed의 Alias | String[] |
key | 동적인 키 값을 사용하는 SpEL 표현식
동일한 cache name을 사용하지만 구분될 필요가 있을 경우 사용되는 값 | String |
condition | SpEL 표현식이 참일 경에만 캐싱 적용
- or, and 등 조건식, 논리연산 가능 | String |
unless | 캐싱을 막기 위해 사용되는 SpEL 표현식
condition과 반대로 참일 경우만 캐싱이 적용되지 않음 | String |
cacheManager | 사용할 CacheManager 지정
(EHCacheCacheManager, RedisCacheManager 등) | String |
sync | 여러 스레드가 동일한 키에 대한 값을 로드하려고 할 경우,
기본 메서드의 호출을 동기화
즉, 캐시 구현체가 Thread Safe하지 않는 경우,
동기화를 걸 수 있는 속성 | boolean |
CachePut
캐시에 값을 저장하는 용도로만 사용
@Cacheable
과 유사하게 실행 결과를 캐시에 저장하지만,
조회 시에 저장된 캐시의 내용을 사용하지는 않고 항상 메서드의 로직을 실행한다.속성 | 설명 | 타입 |
cacheName | 입력할 캐시 이름 | String[] |
value | cacheNamed의 Alias | String[] |
key | 동적인 키 값을 사용하는 SpEL 표현식
동일한 cache name을 사용하지만 구분될 필요가 있을 경우 사용되는 값 | String |
cacheManager | 사용할 CacheManager 지정
(EHCacheCacheManager, RedisCacheManager 등) | String |
condition | SpEL 표현식이 참일 경에만 캐싱 적용
- or, and 등 조건식, 논리연산 가능 | String |
unless | 캐싱을 막기 위해 사용되는 SpEL 표현식
condition과 반대로 참일 경우만 캐싱이 적용되지 않음 | String |
CacheEvict
메서드가 호출 될 때 저장된 캐시를 삭제합니다.
캐싱된 데이터가 변경(CUD)될 경우 기존의 캐싱된 데이터가 바뀌어야 하기 때문에 지워주는 작업
속성 | 설명 | 타입 |
cacheName | 입력할 캐시 이름 | String[] |
value | cacheNamed의 Alias | String[] |
key | 동적인 키 값을 사용하는 SpEL 표현식
동일한 cache name을 사용하지만 구분될 필요가 있을 경우 사용되는 값 | String |
allEntries | 캐시 내의 모든 리소스를 삭제할지의 여부 | boolean |
condition | SpEL 표현식이 참일 경에만 캐싱 적용
- or, and 등 조건식, 논리연산 가능 | String |
cacheManager | 사용할 CacheManager 지정
(EHCacheCacheManager, RedisCacheManager 등) | String |
beforeInvocation | true : 메서드 수행 이전 캐시 리소스 삭제
false : 메서드 수행 후 캐시 리소스 삭제 | boolean |
Caching
하나의 메서드를 호출할 때 Cacheable, CacheEvict 등의 여러 개의 캐싱 동작 수행할 때 사용
속성 | 설명 | 타입 |
cacheable | @Cacheable 배열 등록 | Cacheable[] |
evict | @CacheEvict 배열 등록 | CacheEvict[] |
put | @CachePut 배열 등록 | CachePut[] |
CacheConfig
클래스 단위로 캐시 설정을 동일하게 하고 싶을 때 사용한다.
속성 | 설명 | 타입 |
cacheNames | 해당 클래스 내 정의된 캐시 작업에서의 default 캐시 이름 | String[] |
cacheManager | 사용할 CacheManager 지정
(EHCacheCacheManager, RedisCacheManager 등) | String |
사용해보기
사용 결과
1. 조회
GET
{{base}}/api/v1/users/1

- 결과를 보면 처음 조회만 쿼리와 함께 6ms가 소요되고, 그 후로는 캐시로 조회가 되는 것을 확인할 수 있습니다.
2. 수정 후 조회
PATCH
{{base}}/api/v1/users/1
GET
{{base}}/api/v1/users/1

- 수정 후에 바로 조회하는 경우에도 변경된 상태로 캐시로 저장되기 때문에..
SELECT
가 실행되지 않는다?
💿 Redis
Redis 사용 이유
- 추상화된 API와 어노테이션을 제공
- SpringBoot의 Auto Configuration 적용으로 Cache 서버 설정이 간결
- SpringBoot Starter Kit을 기본으로 제공 (spring-boot-starter-data-redis)
Redis 설정 방법
- 의존성 추가
- Redis 커넥션 정보 설정
- SpringBoot 메인 클래스에 ‘캐시 사용해' 알려주기
- 사용할 메서드에 어노테이션 장착!
- 사용 가즈아