본문 바로가기

성능개선

Request cache 적용

사용자 요청 서비스가 시작되어 종료될 때까지 유지되는 캐시이다. 서비스 요청이 들어와 어플리케이션 시작될 때 캐시가 초기화되어 비어 있고 어플리케이션이 종료될 때 캐시가 지워져 사라지는 구조로 사용자 서비스간에는 데이터 공유가 되지 않는다.

 

[특성]

  •  사용자 서비스 요청 내에서만 유효한 캐시로 요청(Request)마다 자신만의 캐시를 가지는 구조
  • 한 쓰레드에서만 액세스가 이루어지므로 동시성 제어를 위한 락(Lock)을 필요로 하지 않음
  • 한 서비스 요청에서 사용하는 데이터만 캐시하고사용 후 지워지므로 메모리 사용량이 적음
  • 캐시의 라이프사이클이 서비스 요청단위로 짧아서 DB와 데이터 동기화를 고려하지 않아도 됨

 

[구현 시 고려사항]

  • 자바의 경우 캐시가 ThreadLocal이나 Service Context에 위치하도록 함
    (TP 경우는 글로벌 변수로 선언함)
  • 서비스 시작과 종료 시에 캐시가 프레임워크 레벨에서 자동으로 Initialize/clear 되도록 함
  • 한 요청 내에서 대량 건이 조회되거나 다양한 입력 값(데이터 키)으로 빈번하게 사용하여 Hit율이 낮은 형태에는 맞지 않음(즉 Request cache에 대량 데이터가 쌓일 가능성이 있으면 적용 못함)

 

[일반적인 적용 예]

  • 고객 기본정보 캐시: 고객관리 시스템에서는 고객 기본정보 조회가 한 서비스 내에서 반복 호출되는 경우가 있는데 기존에 조회된 데이터 없으면 DB 조회하여 캐시 시킨 후 내보내고, 이미 조회된 데이터가 있으면 캐시된 데이터를 내보냄
  • 보험사 환급요율정보 캐시: 해지환급금 예시표 같은 조회 프로그램은 년도별 환급금을 계산하기 위해 비슷한 조회가 수천 회까지 이루어지는데, 보험사 요율 테이블은 상품 종류에 따라 다양하여 전체 테이블 캐시는 불가능함. 그러나 한 상품의 환급요율은 데이터건수가 적으므로 서비스 요청 단위에서 캐시하여 사용하면 큰 성능개선 효과를 볼 수 있음

 

<적용코드 예>

--------------------------------------------------------------------------------------
1. Cache 모듈 작성
   (ThreadLocal HashMap으로 만드는 것이 핵심 로직임)

 

package com.perf;

 

import java.util.HashMap;

 

public class RequestCache {
  static final private ThreadLocal<HashMap> cache = new ThreadLocal<HashMap>();
 
  static public void initialize(){        // Request 시작 시에 캐시 초기화
    cache.set(new HashMap());
  }
 
  static public void remove(){            // Request 종료 시에 캐시 삭제
    cache.set(null);
  }
 
  static HashMap get(String id){          // ID에 대한 캐시 get 수행(없으면 null 리턴)
    HashMap map = cache.get();              // ID에 대한 개선 지정여부 확인 및 캐시 리턴
    if(map == null)
      return null;
    return (HashMap)map.get(id);
  }
 
  static void set(String id){              // ID에 대해 캐시가 동작하도록 설정 수행
    set (id, 10);
  }
 
  static void set(String id, int size){
    HashMap map = cache.get();
    if(map == null)
      return;
    if(!map.containsKey(id)){
      map.put(id, new HashMap(size));
    }
  }

 

  static void clear(String id){           // ID에 대한 캐시 제거
    HashMap map = cache.get();
    if(map == null)
      return;
    map.remove(id);
  }

 

  static void clearAll(){                 // Request 내에 있는 모든 캐시 제거
    HashMap map = cache.get();
    if(map == null)
      return;
    map.clear();  
  }
}

 

------------------------------------------------------------
2. SQL 수행하는 Framework에 Cache 코드를 적용함
   (아래코드는 이해를 위한 Sample 코드임-Cache 핵심 로직)
  
public LMultiData executeQuery(String sql_id, LData parameters) throws SQLException {
  LMultiData return_data = null;
  LMultiData cache_data = null;
  String cache_key = null;

 

  Map cache = RequestCache.get(sql_id);    // 서비스 시작 부분에 RequestCache.set(sql_id)가
                                                              // 지정되었으면 캐시가 나오고, 아니면 null 리턴
  if(cache != null){                                     // 캐시를 사용하도록 지정된 sql_id이면
    cache_key = parameters.toString();         // 바인드 변수를 기반으로 캐시 키 생성
    cache_data = cache.get(cache_key);     // 캐시에 해당 캐시 키를 가진 데이터 검색
    if(cache_data != null){
      return_data = cache_data.clone();       //  캐시 내 데이터 변경되지 않도록 복제
      return return_data;
    }
  }

 

  ... 쿼리 수행 ....

 

  if(cache != null){                               // 캐시를 사용하도록 지정된 sql_id이면
    cache_data = return_data.clone();    // 새로이 조회된 데이터 복제하여 캐시에 저장
    cache.put(cache_key, cache_data);
  }
  return return_data;
}

 

--------------------------------------------------------------
3. Servlet과 같은 Request 호출 시작부분에 Request cache를 초기화하고 서비스 종료후 삭제하는 코드 적용
   (아래코드는 이해를 위한 Sample 코드임)

 

import com.perf;

 

public class CacheFilter implements Filter {
  @Override
  public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain filterchain) throws IOException, ServletException {
      try {
       RequestCache.initialize();                   // Request Cache 초기화(캐시생성)
       filterchain.doFilter(request, response); // 본 업무처리
      }finally{
        RequestCache.remove();                  // 사용한 Request Cache 제거
      }
  }
}

 

--------------------------------------------------------------
4. 실제 프로그램 모듈에서 Cache 적용코드 추가
   (호출된 서비스 시작부분에 추가하는 것이 중요함)

 

public class SalesMngt extends Command {
  public void proessSale(ServletRequest request, ServletResponse response) {
      RequestCache.set("SCUT0001.retrieveCustInfo");        // 특정 SQL ID에 대해 캐시 동작 지정
      RequestCache.set("SSAL0002.retrieveProductInfo");
      RequestCache.set("SCOM0003.retrieveCommCDInfo");
 
      try {
           … 업무 로직 처리 …
      }catch(Exception es){
     … 생략 …
      }
      … 생략 …
  }
}

'성능개선' 카테고리의 다른 글

채번로직 캐시적용  (0) 2022.11.18
Glance sample 스크립트  (0) 2022.11.18
수식계산기  (0) 2022.11.18
날짜연산 개선  (1) 2022.11.18
자배 배치 모니터링용 소스  (0) 2022.11.18