캐시때문에 머리가 지끈지끈

Nine·2022년 9월 30일
1

✋어떤 일이 있었죠?

달록 서비스를 개발하고 배포하면서 여러 일들이 있었어요.

항상 UI, 컴포넌트, 서비스 개발에만 신경쓰면서 코드를 작성했던터라, 또 netlify같이 배포의 거의 모든 과정을 도와주는 호스팅 서비스를 이용하지 않고 처음으로 직접 Nginx를 설정하여 배포했기에 겪는 어려움들이 많았어요.

😅 가장 먼저 기존 사용자가 새롭게 배포된 달록 서비스를 이용하지 못했습니다.

기능을 업데이트하면서 서비스 버전이 올라가게 되었습니다. 저희 팀은 AWS EC2에 nginx를 올려서 프론트엔드를 배포하고 있어요. 새로운 버전을 출시하기 위해 평상시처럼 배포를 진행하고 달록에 접속했습니다.

배포가 성공적으로 진행되었으나 저희 화면에는 계속 이전 버전의 달록이 보이더라구요.

알고 보니 캐시 무효화가 진행되지 않아 매번 캐싱된 문서를 가져오고 있었던 것입니다.

개발자가 사용자들의 브라우저 캐시에 직접적으로 접근할 수 있는 방법은 없기에 이는 꽤나 심각한 문제였습니다. 최신 버전을 이용하려면 사용자가 직접 캐시를 지우고 새로고침해야하니까요.

😅 또 다른 문제는 성능과 관련된 문제였습니다.

캐시 설정이 없다보니 짧은 시간 내에, 혹은 변하지 않은 유효한 리소스에 대해서도 계속 Request를 보내더라구요.

결론적으로 사용자가 더 많은 Http Request를 보내게 되어 네트워크 환경이 조금이라도 느려지다면 사용자 경험 측면에서 굉장히 좋지 않을 것이 분명했어요.

📗 이를 해결하기 위해 캐시에 대한 공부를 진행했습니다.


HTTP

HTTP는 클라이언트와 서버가 통신하는 프로토콜입니다.

클라이언트와 서버가 통신하는 수단은 HTTP Message입니다.

HTTP Request -> HTTP Response

이 메세지에는 헤더가 존재합니다. 이 헤더에 캐시와 관련된 설정들을 넣어 메세지를 주고 받으면 캐시와 관련된 설정을 적용시킬 수 있을 거예요.


HTTP Cache

Request를 받은 서버는 Response의 유효기간을 정할 수 있어요.

Cache-Control

클라이언트에 어떻게 캐싱할지를 지정합니다.

✋ 캐싱해!

Cache-Control : max-age=31536000

서버에서 Response Header에 Cache-Control 필드를 다음과 같이 작성하면 최대 1년(31,536,000초)간 브라우저 캐시에 리소스를 캐시해요.

만약 클라이언트가 이 기간 내에 다시 같은 리소스를 Request하면 서버에 요청하지 않고 캐시된 리소스를 사용하게 됩니다.

참고) Expires 도 있는데, 절대 유효기간을 지정해요. (그래도 Cache-Control이 Expires 보다 우선순위가 높답니다~)

✋ 잠깐만, 어떻게 그 기간동안 리소스가 유효한지 장담해?

Cache-Control: no-cache
Cache-Control: no-store

no-cache로 설정하면 캐시가 가능하긴하지만 매번 서버에 유효성 검사를 해요.
no-store로 설정하면 아예 캐시가 안됩니다.


Cache 검증

✋ 캐시 검증이 필요한 경우는 다음과 같을 거예요.

캐시를 읽음 -> 유효 기간이 지남 -> 써도 되는지 revalidation(재검증) 요청을 서버에게 보냄

받았던 리소스 (캐싱된 Response)에서 두 가지 경우가 있는데요!

  1. Last-Modiefied가 있다면
  • 재검을 Request할 때 If-Modified-Since필드에 캐시의 Last-Modified값을 넣어줍니다.
  • 서버는 이를 토대로 그 이후의 수정이 있었는지 여부를 알려주게 됩니다.
  1. ETag가 있다면
  • 재검을 Request할 때 If-None-Match필드에 캐시의ETag값을 넣어줍니다.
  • 서버는 보내준 캐시의 Etag와 서버의 Etag가 같은지 비교합니다.

Cache 무효화

✋ 유효기간이긴한데 그래도 클라이언트가 강제로 서버의 최신 데이터를 쓰고 싶어요!

✌ 브라우저 캐시 무효화

결론부터 말씀드리자면 불가능합니다😱

사용자가 직접 브라우저 캐시를 비울 수는 있지만.. (강력 새고로침)

개발자가 직접 사용자들의 브라우저를 비울 수는 없겠죠ㅠㅠ

그래서 처음부터 굉장히 조심스럽게 설정해야겠죠.

✌ CDN 캐시 무효화
해당 플랫폼에서 제공해요.

대표적으로 CloudFront에서는 Invalidation이 있죠.

✌ 캐시 버스팅

  • content/chunk hash : 새로 배포할 때 파일 이름에 hash값을 붙여주면 다르게 인식하겠죠.

  • version : 마찬가지입니다. 파일 이름에 version이나 time stamp를 붙이는 거죠.


HTTP Cache와 CDN

✋ 물론 중간 프록시(e.g. CDN)에도 캐시를 저장할 수 있어요.

Cache-Control: public

이 설정을 통해 최종 끝 클라이언트(브라우저)뿐만 아니라 중간에 있는 친구들도 캐싱할 수 있어요.

Cache-Control: private

그럼 반대로 최종 끝 클라이언트만 캐싱을 가능하게 하려면 반대가 되겠죠?
private가 기본값이예요.

🙌 자 그럼 이 예시를 보시죠.

Cache-Control: public, s-maxage: 31536000, max-age=0

s-maxage는 중간 프록시가 캐싱할 수 있는 기간이겠죠. 1년동안 중간에서 캐싱할 수 있어요.
max-age는 최종 끝 클라이언트에 관한 설정이죠. 이 값이 0이면 브라우저 캐싱은 없겠네요.


조금 더 생각해보기...

캐시 종류가 3개 있다?

멀티버스 개념으로 생각해봅시다.

profile
함께 웃어야 행복한 개발자 장호영입니다😃

0개의 댓글