HTTP 캐쉬로 API 속도 올리기

Heehong Moon
bgpworks
Published in
4 min readFeb 16, 2018

요즘 많은 서비스가 REST API를 제공해서 웹 프론트 또는 모바일앱에서 사용하도록 디자인을 많이 한다. 많이 사용하는 웹서버 또는 프레임웍에서는 Static file(js, css, image)에 자동으로 Cache 처리가 되지만 dynamic rendering이 필요한 곳(REST API)에서는 Cache기능을 사용하지 않게 되어 있다.

API와 같은 Dynamic content에도 간단하게 Cache기능을 사용하게 설정하면 API속도도 증가되고 유저 입장에서는 네트웍 트래픽을 줄일 수 있다.

HTTP Cache

HTTP Cache는 크게 보면 세가지로 나눌수 있는데, 공통적으로 Response Header에 어떻게 넣는냐에 따라 다르게 동작한다. 이 세가지 방식을 정확히 이해하지 않고 사용하게 되면 최악의 경우 유저가 새로운 데이터가 있어도 예전 데이터만 받아오게 될 수도 있다.

1. Cache control + Expire

Cache-Control: public, max-age=31536000 

이 방식은 max-age시간 동안 브라우져가 캐쉬를 해도 무방하다고 알려주는 Cache방식인데, 브라우져 입장에서는 max-age기간 동안 아예 서버에 요청을 안할 수 있다. API의 경우 언제 새로운 데이터가 포함 될지 모르기 때문에 이 방식을 사용할 수 없다.

2. Last Modified

Last-Modified: Mon, 03 Jan 2011 17:45:57 GMT

API의 내용이 마지막으로 변경된 시간을 Response로 주게 되면, 웹브라우져에서는 다음에 동일한 API를 Call하는 경우 아래와 같은 Request Header를 추가해서 보내게 된다.

If-Modified-Since: Mon, 03 Jan 2011 17:45:57 GMT 

그럼 API 핸들러에서 마지막으로 변경된 시간을 체크해서 아직 안바뀐 경우 304 Status코드를 주면 웹브라우져가 이전에 Cache되었던 데이터를 사용하게 된다.

만약 DB에서 마지막 변경된 시간을 관리하고 있다면 이 방식을 사용하면 된다.

3. Etag

Etag 방식은 Last-Modified 방식과 거의 동일한데, 시간 대신 Hash값을 사용한다는 측면에서 다르다. Response 데이터의 MD5 Hash를 보통 사용하며, Last-Modified보다 좀 더 유연하게 적용 가능해서 더 좋은 방식이라고 볼 수 있다.

ETag: "15f0fff99ed5aae4edffdd6496d7131f" 

Response에 다음과 같은 Etag 헤더를 추가해주면, 다음 동일한 API를 부르면 아래와 같은 Request 헤더에 체크하는 헤더가 추가된다.

If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"

Last-Modified와 동일하게 서버에서 같은 ETag를 가지고 있다면 304 를 리턴해주면 된다.

위 세가지 방식 중 Last-Modified, Etag 만 API에 적용가능하다.

1. DB에 데이터의 마지막 수정시간을 가진 경우

DB에서 모든 데이터의 마지막 수정시간을 가진 경우라면 Last-Modified 방식으로 쉽게 구현가능하다.

  1. If-Modified-Since보다 이후에 변경된 데이터가 있는지 체크
  2. 만약 없다면 304로 바로 리턴
  3. 이후 변경된 데이터가 있다면 기존과 동일하게 Response데이터를 만들고 Last-Modified를 마지막 변경시간으로 변경

이 방식은 여러가지 Table을 Join 하지 않고 비교적 가져오려는 데이터가 간단한 경우만 적용된다고 볼 수 있다. 왜냐면 Join이 되는 경우 거의 모든 Table에서 마지막 수정일을 가지고 있어야 하고, 이를 체크하는 쿼리를 하는것도 쉽지 않기 때문이다.

2. ETag로 데이터 전송 시간 절약

API데이터의 MD5 Hash를 ETag로 사용하게 되면 DB부하를 줄일 순 없지만, Response 시간을 줄이는데 도움이 될 수 있다.

  1. API 핸들러 처리(DB query)
  2. 결과 Json에 MD5 Hash
  3. If-None-Match 헤더에 있는 값과 hash값을 비교
  4. 만약 동일하다면 304로 리턴
  5. 다르다면 200에 결과 Json리턴

결론

API와 같이 언제 바뀔지 모르는 데이터의 Cache는 쉽지 않은데, Last-Modified방식 또는 Etag를 이용하면 서버에서 새로운 데이터를 먼저 확인하고 줄 수 있기 때문에 API에도 충분히 적용가능하다.

DB의 부하가 많아지면 일반적으로 Redis, Memcached로 캐쉬를 먼저 하려고 하는데, 그보다 먼저 HTTP Cache로 부하를 먼저 줄여보는게 좋다. DB부하를 줄일 수 있을 뿐 아니라 Response 데이터를 다시 받아오지 않아도 되기 때문에 API속도도 덤으로 개선된다.

--

--