티스토리 뷰

웹 캐시


웹 캐시(영어: web cache) 또는 HTTP 캐시(HTTP cache)는 서버 지연을 줄이기 위해 웹 페이지, 이미지, 기타 유형의 웹 멀티미디어 등의 웹 문서들을 임시 저장하기 위한 정보기술이다. 웹 캐시 시스템은 이를 통과하는 문서들의 사본을 저장하며 이후 요청들은 특정 조건을 충족하는 경우 캐시화가 가능하다. 웹 캐시 시스템은 일종의 어플라이언스나 컴퓨터 프로그램을 의미할 수 있다. 동일한 서버에 다시 접근할 때에는 근처에 있는 프록시 서버의 웹 캐시에 저장된 정보를 불러오므로 더 빠른 열람이 가능하다.[위키백과]

웹 캐시의 장점


웹 캐시를 사용하면 클라이언트가 원(Origin) 서버에 정적 콘텐츠를 요청하지 않는 덕분에 얻을 수 있는 몇 가지 장점이 존재한다

불필요한 데이터 전송 감소

불필요한 데이터 전송은 네트워크 대역폭을 잡아먹고 데이터 전송을 느리게 만들며 서버에 부하를 준다. 서버가 클라이언트에게 동일한 데이터를 반복적으로 전달하는 경우 웹 캐시를 사용하면 불필요한 데이터 전송을 줄일 수 있다

갑작스러운 요청 증가에 따른 대응

한 번에 많은 클라이언트가 원 서버에 요청을 하면 트래픽이 급증하게 되어 네트워크와 서버에 심각한 장애를 일으킬 수 있다. 웹 캐시를 사용하면 정적 콘텐츠에 대한 요청이 원 서버에 전달되지 않으므로 네트워크와 서버의 장애를 방지할 수 있다

거리로 인한 지연 감소

빛은 1초에 약 30만 킬로미터를 이동한다. 매우 빠른 속도이지만 빛의 속도로인한 피할 수 없는 지연이 발생한다. 웹 캐시를 사용하면 클라이언트와 서버간 유의미한 거리차가 존재할 경우 지연을 줄일 수 있다

웹 캐시의 종류


Private Cache

브라우저에서 제공하는 캐시로 브라우저 캐시라고도 한다. 대부분의 웹 브라우저는 캐시를 내장하며, 많은 공간을 필요로하지 않는다. 사용자가 캐시의 크기가 설정을 수정할 수 있다

Public (Proxy) Cache

캐싱을 제공하는 프락시 서버를 의미한다. 여러 사용자가 접근하기 때문에 Private Cache에 비해 더 많은 불필요한 트래픽을 줄일 수 있다.

캐시 처리 단계


1. 요청 받기

  • 네트워크 커넥션에서의 활동을 감지하고 들어오는 데이터를 읽는다

2. 파싱

  • 요청 메시지를 파싱하여 헤더 부분을 조작하기 쉬운 자료구조에 담는다

3. 검색

  • URL을 알아내고 해당하는 로컬 사본이 있는지 확인한다
    • 사본은 메모리나 디스크 심지어 근처의 다른 컴퓨터에 위치할 수도 있다
  • 문서를 로컬에서 가져올 수 없다면 상황이나 설정에 따라 원 서버나 부모 프락시에서 가져오거나 실패를 반환한다
  • 캐시된 객체는 서버 응답 본문과 원 서버 응답헤더를 포함하고 있다
    • 캐시 적중동안 올바른 서버 헤더가 반환될 수 있다
    • 얼마나 오랫동안 캐시에 머물고 있었는지, 얼마나 자주 사용되었는지 등에 대한 메타데이터를 포함한다

4. 신선도(freshness) 검사

  • HTTP는 캐시가 일정 기간 동안 원 서버 문서의 사본을 보유할 수 있도록 해준다
    • 이 기간 동안 해당 사본은 신선한 것으로 간주된다
    • 일정 기간이 지나면 해당 사본은 신선하지 않은 것으로 간주되어 재검사를 실시해야 한다

5. 응답 생성

  • 캐시는 캐시된 서버 응답 헤더를 토대로 응답 헤더를 생성한다
  • 캐시는 클라이언트에 맞게 헤더를 조정해야 하는 책임이 있다

6. 전송

  • 응답 헤더가 준비되면, 캐시는 응답을 클라이언트들에게 전달한다

7. 로깅

  • 대부분의 캐시는 로그 파일과 캐시 사용에 대한 통계를 유지한다

유효 기간과 나이


캐시에 저장된 콘텐츠들이 만료가 되었는지(원 서버에 재검사를 요청해야하는 지) 판단 하기 위해 HTTP는 Cache-Control: max-ageExpires 헤더를 제공한다

  • Cache-Control: max-age
    • 캐시에 저장된 콘텐츠의 최대 나이를 설정한다
    • Cache-Control: max-age=30 처럼 작성하며 초 단위이다
  • Expires
    • 캐시에 저장된 콘텐츠의 절대적인 유효 기간을 명시한다
    • Expires: Wed, 21 Oct 2015 07:28:00 GMT 처럼 절대적인 날짜를 명시한다
    • Cache-Control 헤더가 존재하는 경우 무시된다

조건부 메서드와 재검사


HTTP는 If-XXX-XXX와 같은 조건부 메서드 헤더를 제공한다. 조건부 메서드를 통해 캐시는 서버에게 조건부 GET를 요청할 수 있고, 캐시에 저장된 콘텐츠와 원 서버의 데이터가 달라졌을 경우 콘텐츠를 응답 받을 수 있다

If-Modifed-Since

응답의 Last-Modified 헤더와 함께 동작한다. Last-Modified는 콘텐츠의 마지막 수정 일시를 의미한다. 클라이언트는 콘텐츠의 마지막 수정 일시를 전달받아 저장하고 있고, 캐시가 만료된 경우 If-Modified-Since 헤더에 저장하고 있던 마지막 수정 일시를 담아 요청한다. 서버는 요청으로 전달 받은 날짜와 실제 콘텐츠의 수정 일시를 비교하여 수정 되지 않은 경우 304 Not Modified를 응답하고(BODY 미포함), 수정된 경우 콘텐츠를 전송한다.

시간을 이용한 재검사 방법은 아래와 같은 경우에는 사용하기 어렵다

  • 일정 시간 간격으로 콘텐츠가 재작성 되지만 내용에 변화가 없는 경우
  • 1초보다 작은 간격으로 콘텐츠가 수정되는 경우
  • 콘텐츠가 변경되었지만 철자나 주석처럼 유의미 하지 않는경우

If-None-Match

If-Modified-Since, Last-Modified 를 이용한 재검사가 어려운 경우 사용할 수 있는 방법이다. 캐싱될 데이터의 고유 해시값인 ETag를 사용한다. 클라이언트는 서버에게 ETag 헤더에 값을 전달받고 저장한다. 그리고 캐시가 만료된 경우 If-None-Match에 가지고 있던 값을 담아 요청하고 서버는 단순히 헤더에 담긴 값과 실제 값을 비교하여 다른 경우 콘텐츠를 응답하고, 같은 경우 304 Not Modified를 응답한다

304 Not Modified

304 Not Modified는 원 서버이 콘텐츠가 변경되지 않았음을 의미한다. 응답 바디는 비워두고 헤더만 전달하기 때문에 네트워크 대역폭을 효율적으로 사용한다.

캐시 제어


Cache-control: max-age 이외에 캐시를 제어하기 위한 여러가지 헤더를 제공한다.

  • Cache-Control: no-store
    • 데이터에 민감한 정보가 있으므로 저장하면 안됨
    • 메모리에서 사용하고 최대한 빨리 삭제
  • Cache-Control: no-cache
    • 데이터는 캐시에 저장해도 되지만 항상 원 서버에 검증하고 사용
  • Cache-Control: must-revalidate
    • 캐시 만료 후 최초 조회시 항상 원 서버에 검증 해야함
    • 원 서버에 접근할 수 없는 경우 프록시는 항상 504 Gateway Timeout을 응답해야 함
      • 프록시 캐시를 사용하는 경우 프록시의 설정에 따라 원 서버에 문제가 발생하더라도 프록시에서 클라이언트에게 200 OK와 같은 응답을 하는 경우가 있다

캐시 무효화

캐시 무효화를 하기 위해서는 Cache-control: no-store, no-cache, must-revalidate 처럼 작성한다. 하위 호환을 위해서 Pragma: no-cache도 추가할 수 있다.

스프링 캐시


스프링은 AOP 방식으로 편리하게 메소드에 캐시를 적용할 수 있도록 추상화를 제공하며, 아래와 같은 몇가지 캐시 구현체를 제공한다

  • JDK ConcurrentHashMap based Cache
  • Ehcache-based Cache
  • Gemfire-based Cache
  • Caffeine Cache
  • JSR-107 Cache

그리고 스프링의 org.springframework.cache.Cache, org.springframework.cache.CacheManager 가 스프링 캐시 추상화의 핵심적인 역할을 한다. CacheManager 인스턴스는 하부 캐시 솔루션이 제공하는 캐시 매니저를 감싸는 래퍼 역할을 하며, Cache 인스턴스를 관리한다. Cache 인스턴스는 하부 캐시를 감싸며, 하부 캐시와 상호 작용하는 메서드를 제공한다

Spring 캐시 사용하기

1. @EnableCaching 추가

@EnableCaching
@SpringBootApplication
public class SpringCacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCacheApplication.class, args);
    }
}

2. 캐시 매니저 빈 등록

  • ConcurrentMapCacheManager: Java의ConcurrentHashMap을 사용해 구현한 캐시를 사용하는 캐시매니저
  • SimpleCacheManager: 기본적으로 제공하는 캐시가 없어 사용할 캐시를 직접 등록하여 사용하기 위한 캐시매니저
  • EhCacheCacheManager: 자바에서 유명한 캐시 프레임워크 중 하나인 EhCache를 지원하는 캐시 매니저
  • CompositeCacheManager: 1개 이상의 캐시 매니저를 사용하도록 지원해주는 혼합 캐시 매니저
  • CaffeineCacheManager: Java 8로 Guava 캐시를 재작성한 Caffeine 캐시를 사용하는 캐시 매니저
  • JCacheCacheManager: JSR-107 기반의 캐시를 사용하는 캐시 매니저

3. 캐시 어노테이션 사용

@Cacheable

  • 캐시에 데이터가 없을 경우에는 기존의 로직을 실행한 후, 캐시에 데이터를 추가하고, 캐시에 데이터가 있으면 캐시에 저장된 데이터를 반환한다
  • key 속성은 반환한 값을 캐시에 저장할 때 사용할 키를 의미한다
    • key를 지정하지 않으면 기본적으로 스프링의 SimpleKeyGenerator 클래스를 사용한다
    • SimpleKeyGenerator는 메서드 시그니처와 인수를 사용해 키를 생성한다
      • 메서드에 전달한 인수가 모두 같을때는 @Cacheable을 설정한 메서드를 호출하지 않는다
      • 인자가 없을 경우에는 기본값인 0을 key로 하여 저장한다
      • 인자가 여러개인 경우 인자의 hashCode값을 조합하여 key로 설정한다
  • cacheNames 속성은 반환한 값을 캐시할 캐시 영역을 지정한다
  • condition 속성은 특정 조건일 때만 캐시를 적용할 때 사용한다

@CacheEvict

  • 캐시에 있는 데이터를 비울 때 사용한다
  • cacheNames는 비울 캐시의 영역을 의미한다
  • condition은 조건에 따라 캐시를 비울 때 사용한다
  • allEntries는 지정한 캐시 영역의 모든 엔트리를 비울 지 일부만 비울지 지정한다
  • beforeInvocation은 캐시를 메서드 실행 이전이나 이후 중 언제 비울지 결정한다

@CachePut

  • 항상 메서드를 호출해서 반환 값을 넣을 때 사용한다
    • Cacheable과 다르게 항상 메서드가 호출된다
728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함