Spring Boot - Cache
· 4 min read
**캐시(cache, 문화어: 캐쉬, 고속완충기, 고속완충기억기)**는 컴퓨터 과학에서 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다.
Spring의 장점 중 PSA(Portable Service Abstractions)라는 것이 있다. 이는 쉬운 서비스 추상화라고 하는데, 각각의 외부 서비스를 간단한 인터페이스만으로 쉽게 사용할 수 있도록 설계되어있다. Cache에서는 Redis, Ehcache, ConcurrentMap 등을 CacheManager
인터페이스로 추상화되어 있고, CacheManager
인터페이스를 이용하여 또 다른 cache 라이브러리를 사용할 수도 있다.
언제 사용하면 좋을까?
아래 그림과 같은 메뉴가 단적인 예시가 될 수 있다.
- 무거운 비즈니즈 로직을 수 행할 떄
- 주기적으로나 언제나 동일한 데이터를 가질 떄
- RDB에 대한 부하를 분산하고자 할 때
Dependency
dependencies {
compile('org.springframework.boot:spring-boot-starter-cache')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Config
@EnableCaching
을 명시해주면 바로 사용할 수 있고 추가적인 설정이 없다면 ConcurrentMap
를 사용하여 Caching하게 된다. 또한 Redis나 Ehcache 라이브러리를 추가하면 Spring Boot의 Auto Detect 기능으로 인해 해당 라이브러리를 자동적으로 이용하게 된다.
@Configuration
@EnableCaching
public CacheConfig {
}
Component
무거운 비즈니스 로직이 있다고 가정하고 약 3초의 sleep을 주도록 해보자. 아래 코드를 간단히 설명하자면, book이라는 캐시 영역에 isbn을 키로 갖는 데이터를 Caching 해두는 것이다.
@Component
public class SimpleBookRepository implements BookRepository {
private static final Logger logger = LoggerFactory.getLogger(SimpleBookRepository.class);
@Override
@Cacheable(value="book", key="#isbn")
public Book getByIsbn(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book");
}
private void simulateSlowService() {
try {
long time = 3000L;
Thread.sleep(time);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
@Override
@CacheEvict(value="book", key="#isbn")
public void refresh(String isbn) {
logger.info("cache clear => " + isbn);
}
}
@Cacheable
: 캐시 생성
- value: 캐시 이름
- key: 키
@CacheEvict
: 캐기 초기화
- value: 캐시 이름
- key: 키
Test Code
로직에 대한 소요시간을 측정해 보았다.
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootCacheApplicationTests {
@Autowired
private BookRepository repository;
private long startTime;
private long endTime;
private static final Logger logger = LoggerFactory.getLogger(SpringBootCacheApplicationTests.class);
@Before
public void onBefore() {
startTime = System.currentTimeMillis();
}
@After
public void onAfter() {
endTime = System.currentTimeMillis();
logger.info("소요시간: {}ms", endTime - startTime);
}
@Test
public void test1() {
repository.getByIsbn("a");
}
@Test
public void test2() {
repository.getByIsbn("a");
}
@Test
public void test3() {
repository.getByIsbn("b");
}
@Test
public void test4() {
repository.getByIsbn("a");
}
@Test
public void test5() {
repository.refresh("a");
repository.getByIsbn("a");
}
}
결과
소요시간: 3215ms
소요시간: 10ms
소요시간: 3006ms
소요시간: 8ms
cache clear => a
소요시간: 3017ms