Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Info

캐싱은 웹기술뿐만 아니라, 디스크/메모리가 동시에 탑재된 여러가지 컴퓨터장치에서

성능을 위해 활용되는 기술입니다. 디스크는 상대적으로 속도가 느리기 때문에

반복적으로 발생하는 변경없는 데이터의 Read에대해 , 메모리가 일정시간 저장하고 있다가

디스크또는 네트워크에 부하를 주지않고 빨리 반환하는 기술이라고 볼수 있으며 응답이 중요한 웹에서도 중요한 요소입니다.

Table of Contents


캐시 기초개념

...


일반적 인 캐시처리 방식

Write-through with no-write-allocationWrite-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
titleApplication에 @EnableCaching 지정
@SpringBootApplication 
@EnableCaching 
public class Application { 
......,


사용스텝2.

Code Block
languagejava
themeEmacs
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초)에 했다고 가정해봅시다.

  • A사용자 최근 게시물 100개 조회 ( 0번노드)
  • B사용자 최근 게시물 100개 조회 ( 1번노드)
  • C사용자 최근 게시물 100개 조회 ( 2번노드)

웹서비스에는 노드밸런스란 기능이있어서 사용자를 각각 다른노드로 분배를시킵니다.

이것은 대부분의 웹서비스가 사용하는 방식입니다.

이와 같은 상황에서 문제가 무엇일까요? 각 노드에 DB호출수를 줄이기위해

각각의 서버에 캐시기능을 적용하였지만, 캐시기능은 아무런 쓸모없이

설정한 캐시시간을 무시하고, 동일한 데이터 조회를 연속으로 하게됩니다.

이때 필요한 캐시기능이, 여러노드에서도 중복호출을 막는 클러스터 캐시입니다.

...