Page History
Info |
---|
캐싱은 웹기술뿐만 아니라, 디스크/메모리가 동시에 탑재된 여러가지 컴퓨터장치에서 성능을 위해 활용되는 기술입니다. 디스크는 상대적으로 속도가 느리기 때문에 반복적으로 발생하는 변경없는 데이터의 Read에대해 , 메모리가 일정시간 저장하고 있다가 디스크또는 네트워크에 부하를 주지않고 빨리 반환하는 기술이라고 볼수 있으며 응답이 중요한 웹에서도 중요한 요소입니다. |
Table of Contents |
---|
캐시 기초개념
...
일반적 인 캐시처리 방식
Write-through with no-write-allocation | Write-back with write-allocation |
---|---|
...
사용자가 뭔가 정보갱신이 안되고 있다라고 의심을 한다고하면 캐싱기능을 검토해야할것입니다.
웹응답을 높이기위한 CACHE종류
- 브라우져 레벨의 캐시기능 ( 동일 요청에 대해 일정시간 이내 요청없이 스토어된 데이터로 처리 )
- Proxy,장비 캐시기능(Proxy,라우터등에서 지정된 시간이내 동일 요청에 대해 메모리 반환처리)
- 웹 서비스(서버) 레벨에서의 캐시구현 ( 직접 구현)
여기서는 좀더 커스텀하고/디테일한 캐싱처리가 가능한 웹서비스에서 캐싱처리를
직접 구현하는 방법을 살펴보겠습니다.
웹서버 캐시처리방법
- 자신의 노드에서만 메모리 캐시처리
- Redis등 메모리DB 사용하여, 전체 분산노드에 캐시기능 확장
간단한 캐시기능 적용(자신의노드에서만)
...
활용할 캐시 라이브러리
No Format |
---|
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> |
사용스텝1.
Panel | ||
---|---|---|
| ||
......, |
사용스텝2.
Code Block | ||||
---|---|---|---|---|
| ||||
package com.example.demo.data2; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Component; @Component public class SimpleUserRepository { @Cacheable("books") public String getByIsbn(String isbn) throws Exception { long time = 3000L; Thread.sleep(time); return "Some String-" +isbn; } } |
...
- 동일요청 캐싱시간을 최대 몇초유지할지?
- 전체 캐시데이터를 몇개까지 최대 보관할지?
- 데이터 변경시 캐싱데이터를 무효화 시킬지?
- 캐싱에 관여하는 인자값 키처리를 별도로 지정할지?
더 복잡한 캐시처리
Info |
---|
SQL 하나를 호출하기 위한 인자값이 7개정도가 되며 , RESTAPI를 통해 서비스를 한다고 가정해봅시다. 다양한 변수가 생길수 있는 상황에서 DB를 덜 호출하기 위해서 기본캐시기능에서 몇가지 요소가 필요합니다.
|
Caffeine 캐시준비
Code Block |
---|
# application.property spring.cache.cache-names: instruments, directory spring.cache.caffeine.spec: maximumSize=1000, expireAfterAccess=10s // 초(s) 분(m) 일(d) logging.level.com.memorynotfound=info # pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <!-- caching provider --> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency> |
...
이 설정으로, 10초동안 동일요청에대해 빠른 응답처리가 가능해집니다.
검색인자값정의
Code Block |
---|
public class InputOpt { .............................생략 private int ecode; public int getEcode() { return hashCode(); } @Override public int hashCode() { HashCodeBuilder builder = new HashCodeBuilder(); builder.append(category1); builder.append(router); builder.append(action); builder.append(sort); builder.append(sortdir); builder.append(size); builder.append(userprofile); return builder.toHashCode(); } } |
...
이 식별자는 캐시를 할지 말지 판단하는 중요한 판별기능에 요소로 사용이됩니다.
캐시 서비스 정의
Code Block |
---|
//인터페이스 정의 public interface GoodsDataService { Iterable<GoodsDataRC> findAll( BooleanBuilder searchOpt , Pageable pageRequest , InputOpt inputopt ); } ----- 파일분리 //구 현 @Service @CacheConfig(cacheNames = {"directory", "instruments"}) public class GoodsDataServiceImpl implements GoodsDataService{ static final Logger logger = LoggerFactory.getLogger(GoodsDataService.class); @Autowired private GoodsDataRCRepo goodsDataRCRepo; // 이것은 읽기전용의 JPA Repository @Cacheable( value="instruments", key="#inputopt.ecode" ) public Iterable<GoodsDataRC> findAll( BooleanBuilder searchOpt , Pageable pageRequest , InputOpt inputopt ) { logger.info("hash == %d",inputopt.hashCode() ); return goodsDataRCRepo.findAll(searchOpt,pageRequest); } } |
...
우리가 정의한 inputopt.ecode 를통해, 중복처리에대해 캐시 처리가 될것입니다.
캐시 DB사용하기
Code Block |
---|
@Autowired GoodsDataService service; //for cache db ....................... Iterable<GoodsDataRC> dbResult = service.findAll(searchOpt,pageRequest,inputOpt); |
...
http://javasampleapproach.com/spring-framework/cache-data-spring-cache-using-spring-boot
캐시기능을 여러노드에 공통적으로 확장하기
...
Info |
---|
동일한 DB요청을 각각 다른 사용자가 동일시간(+-5초)에 했다고 가정해봅시다.
웹서비스에는 노드밸런스란 기능이있어서 사용자를 각각 다른노드로 분배를시킵니다. 이것은 대부분의 웹서비스가 사용하는 방식입니다. 이와 같은 상황에서 문제가 무엇일까요? 각 노드에 DB호출수를 줄이기위해 각각의 서버에 캐시기능을 적용하였지만, 캐시기능은 아무런 쓸모없이 설정한 캐시시간을 무시하고, 동일한 데이터 조회를 연속으로 하게됩니다. 이때 필요한 캐시기능이, 여러노드에서도 중복호출을 막는 클러스터 캐시입니다. |
...