빨간색코딩

AWS S3 비용 절감하기 (feat. 크로미움 favicon cache 버그) 본문

Web

AWS S3 비용 절감하기 (feat. 크로미움 favicon cache 버그)

빨간색소년 2020. 6. 20. 03:24

1. 들어가며

  • 여기서 말하는 s3 비용절감은 대규모 서비스용도가 아니다. 그런 서비스들은 앞단에 AWS CloudFront 같은 CDN으로 서빙해야하는 게 맞고 그렇게들 하고있을테니, s3와 직접적으로 관련이 없다.
  • 사이드 프로젝트에서 비용을 소소하게 아껴본 경험을 이야기해보고자 한다.
    • 이용자 수가 어느정도 있는 경연, 사이드프로젝트, 데모 등
    • 앞단에 뭔가 대는게 오히려 더 비용이 아까운 상황

2. aws s3 요금 계산식

  • 서울 리전, 20년 6월기준
  • 저장 0.025 USD / GB
  • 전송량 0.126 USD / GB
    • 1 GB 까진 무료
  • 요청량
    • READ 10000번 당 0.0035 USD
    • WRITE 1000번 당 0.0045 USD

3. 문제발생

  • s3 를 이미지 스토리지, 서빙 용도로 사용하고 있다. GET에 대해서만 public으로 정책을 변경했으며, 서비스페이지에서 s3 경로를 직접 참조한다.
    • 컨텐츠의 이미지, 유저 이미지, favicon, opengraph 이미지
  • 기대상황: s3 에서 etag 를 통한 브라우저 캐시를 걸어주니, 유저가 캐시를 삭제하거나, 배포를 통해 buildtime 이 바뀌지 않는 이상 요청이 크게 안 들어올 것이다.
  • 실제 read 요청량 (이용자 수가 늘어나는 상황임)
    • 2월 : 6,928
    • 3월 : 21,527
    • 4월 : 56,654
    • 5월 : 176,137
  • 요청량 그래프를 보고 그냥 넘어갈 수도 있었지만, google analytics 에서 월간 PV를 보니 뭔가 비례한다는 점에서 이상함을 느꼈다. 브라우저 캐시가 제대로 안되고 있나?

3-1. 크로미움에서 favicon 을 캐시하지 않는다?

  • 크롬 개발자도구 네트워크 창에서 대부분 이미지들이 memory, disk cache 되고 있었으나, favicon.ico 파일만은 계속 실제 요청을 날리고 있었다.
  • 버그항목을 찾아보니..https://bugs.chromium.org/p/chromium/issues/detail?id=969033
  • 이 때문에, favicon.ico 으로 많이 요청이 들어가고 있던 것이다.
  • 이 상태로 둔다면, 브라우저 캐시로 줄일 수 있었던 요금을 괜히 더 내야하는 것이다.

4. 어떻게 풀었나요?

  • s3 경로를 직접 참조하는 방식에서, 서비스 서버의 nginx proxy cache 를 활용하여, 캐시된 이미지를 서빙하였다.
  • 그 결과, 5월보다 이용자 수가 늘었음에도 6월 read 요청량이 약 4만대로 줄었다.

4-1. nginx proxy cache

  • docs :http://nginx.org/en/docs/http/ngx_http_proxy_module.html

  • 뒷단 서버로 부터 전달받는 데이터를 cache 하여 서빙한다. 뒷단 서버가 받는 요청량을 줄여줄 수 있다. 여기서는 뒷단서버가 AWS S3 이다.

  • 관련 설정

    • proxy_cache_path : 캐시된 파일을 저장할 디렉터리와 옵션들을 설정할 수 있다.
      • levels : 하위 디렉터리의 수를 나타낸다.
      • keys_zone : cache 명과 공유 메모리 영역의 크기를 지정
        • 가이드에 따르면 1MB면 약 8,000개의 key를 저장할 수 있다고 한다.
        • nginx 는 공유 메모리에서 존재여부를 먼저 확인한 후, 실제 캐시의 위치를 찾는다.
      • inactive : 사용되지 않는 캐시파일 만료 기간
      • max_size : 전체 캐시파일의 크기
    • proxy_cache_key : 캐시 키 포맷 설정
    • proxy_cache_valid : 해당 응답코드에 대해 지정된 시간동안 뒷단으로 요청보내지 않고 캐시하는 설정
    • proxy_cache : 사용할 cahce zone을 지정
  • 캐시 상태 파악

    • ngx_http_upstream 모듈이 제공하는 $upstream_cache_status 를 통해 캐시 상태를 파악할 수 있다.
    • HIT : proxy_cache_valid 내에 있으며, 캐시 파일로 서빙했다.
    • EXPIRED : proxy_cache_valid 내에 없어서, 뒷단에 다녀와서 캐시파일을 갱신했다
    • MISS : 캐시파일이 없어서, 뒷단에서 요청해왔다.
    • 이외에도 몇가지 있으나, 잘 안쓰임
    • 참고 : 응답헤더도 브라우저 캐시되므로,X-Cache-Status: EXPIRED가 계속 보일 수도 있다.
  • 전체 설정

http {
    ...

    proxy_cache_path /devljh/app/nginx/cache/image levels=1:2 keys_zone=image_cache:10m inactive=1d max_size=128M;
    proxy_cache_key "$host$request_uri";

    ...

    server {
        ...

        location ~* \.(gif|png|jpg|jpeg|ico)$ {
            proxy_pass https://{bucket}.s3.ap-northeast-2.amazonaws.com;

            proxy_ignore_headers "Set-Cookie";
            proxy_hide_header "Set-Cookie";
            proxy_set_header cookie "";
            proxy_hide_header x-amz-id-2;
            proxy_hide_header x-amz-request-id;

            proxy_cache_valid 200 1h;
            proxy_cache image_cache;

            expires 1M;
            add_header Pragma public;
            add_header Cache-Control "public";
            add_header X-Cache-Status $upstream_cache_status;
        }

        ...
    }
}
Comments