[AWS] s3에서 새로운 객체로 덮어쓰기 했으나 이전 파일이 보이는 문제

effiRin·2023년 2월 5일
0

AWS

목록 보기
1/5
post-thumbnail

문제 상황

  • 이미지 수정이 발생했을 때 즉각적으로 반영되어야 하는 기능을 개발하고 있다.
    수정은 S3에 업로드할 때 덮어쓰기를 하는 방식으로 진행했다.

  • 그래서 AmazonS3의 putObject() 메소드를 활용하여 동일한 경로, 동일한 이름으로 새로운 이미지 파일을 업로드 했다.

  • 수정 시간이 변경된 것을 확인했으며, 또한 s3에서 '열기'를 하여 새로운 이미지 파일로 덮어쓰기된 것까지 확인했다.

  • 그런데... 해당 이미지를 s3에서 불러오는 path를 브라우저에 입력하여 확인해보니... 덮어쓰기 전 이미지가 나왔다...




원인 찾기

1. AWS s3의 최종 일관성으로 인한 문제 ➡️ but, 2020/11 업데이트 이후 해결된 이슈 (원인 X)

S3 및 기타 대규모 분산 시스템의 더 흥미롭고 때로는 다소 혼란스러운 측면 중 하나가 바로 일반적으로 최종 일관성이라고 하는 개념입니다. 간단히 말해서 데이터를 저장하거나 수정하는 PUT과 같은 S3 API 함수를 호출한 후에는 데이터가 허용되고 안정적으로 저장되었지만 모든 GET 또는 LIST 요청에는 아직 표시되지 않는 약간의 시간 지연이 있습니다.

1) 어플리케이션이 PUT API 함수로 "1"이란 object를 넣고
2) GET API로 이 객체를 불러왔을 때 "1"이 반환된다.
3) 이때, 다시 한번 PUT API 함수로 "2"란 object를 넣어 수정한다면
4) GET API로 불렀을 때 "1"(이전 값) 또는 "2"(수정된 값)가 반환되는 현상 발생.
5) 그러나 일정 시간이 흐른 후에는 수정된 값 "2"가 일관적으로 반환된다.


  • 간단히 말하자면...

[Re2020] S3가 더 넓은 범위의 Strong Consistency 모델을 제공합니다 (Feat. S3 업데이트 이모저모)

S3는 이렇게나 중요한 서비스이기 때문에, 기본적인 동작 특성을 명확히 이해할 필요가 있습니다. 그 중 가장 대표적인 것으로 Eventually Consistency라는 개념이 있습니다. 최종 일관성을 제공한다는 뜻인데요. 이는 쉽게 말해 "특정 요청에 대한 응답의 일관성을 언젠가는 보장하나, 보장할때까지 일정 시간이 소요될수도 있다"라는 뜻입니다. 일례로, 같은 Key로 된 Object를 덮어쓰기(Overwrite)하고 나서, 빠른 시간에 GET 요청을 했을때 최종 일관성이 보장되기 전까지 예전 데이터를 반환할 수도 있다는 뜻입니다.

이처럼 s3 상에서의 수정은 즉각 반영되었지만, 빠른 시간 내에 GET과 같은 요청을 했을 때 일정 시간동안 반영되지 않다가, 나중에 반영되는 것이 '최종 일관성'이다. 그래서 즉각적으로 일관성을 유지할 필요가 있는 어플리케이션의 경우, 즉시 일관성을 제공하는 S3Guard와 같은 것을 추가적으로 이용했다.


  • 그런데 중요한 것은, 이 최종 일관성(Eventually Consistency) 이슈는 2022년 11월 업데이트 이후 해결되어 신경쓸 필요 없는 특성이라는 것이었다.

이번 업데이트로 객체(Object) 기준 PUTS(신규 또는 덮어쓰기 모두)와 DELETE 작업 모두 Strongly Consistency 모델을 제공하기 시작했습니다. 즉, 기존에는 덮어쓰기 후 읽기(GET) 요청시 일정 시간동안 이전 데이터를 읽어올 가능성도 있었으나, 앞으로는 덮어쓰기된 최신 데이터를 반환하게 됩니다. 삭제(DELETE) 후 읽기(GET) 요청 또한 기존에는 삭제 후에도 삭제 전 데이터를 읽어올 가능성이 있었으나, 앞으로는 그럴 가능성이 없는 셈입니다.

그렇다면 이런 변경사항이 적용되는 대상이 어떻게 될까요?
기존 버킷과 신규 버킷 모두 구분 없이 적용됩니다. 사용자가 별도로 무엇을 활성화할 필요도 없습니다. 모든 리전의 버킷에 즉시 적용됩니다. 만일 어플리케이션에서 즉시 일관성을 보장하기 위해 S3Guard와 같은 것을 사용중이었다면, 이제는 그런 추가 계층을 사용할 필요가 없어졌습니다.

이는 모든 기존 S3 객체는 물론 새 S3 객체에 적용되고 모든 리전에서 작동하며 추가 비용 없이 사용할 수 있습니다! 성능에 영향을 미치지 않으며, 원하는 경우 초당 수백 번 객체를 업데이트할 수 있고 전역 종속성이 없습니다.



✔ 2. CloudFront의 캐시 문제 (이게 원인!)

CloudFront에서 업데이트된 Amazon S3 콘텐츠 푸시

Q. Amazon CloudFront를 사용하여 Amazon Simple Storage Service(Amazon S3)에 저장된 객체를 제공하고 있습니다. Amazon S3에서 객체를 업데이트했지만, CloudFront 배포는 여전히 이 파일의 이전 버전을 제공합니다. Amazon S3 콘텐츠가 CloudFront에서 업데이트되지 않는 이유는 무엇입니까?

A. 기본적으로 CloudFront는 24시간(86,400초의 기본 TTL) 동안 Amazon S3에서 응답을 캐시합니다. 24시간 이내에 Amazon S3 응답을 제공하는 엣지 로케이션에 요청이 도달하는 경우 CloudFront는 캐시된 응답을 사용합니다. 이는 Amazon S3에서 콘텐츠를 업데이트한 경우에도 발생합니다.

위 공식 문서에서 내가 겪는 이슈와 똑같은 현상을 언급하고 있었다.
CloudFront에서는 기본적으로 24시간 간격으로 캐싱을 하고 있기 때문에, 업데이트하고 24시간 이내에 GET 요청을 했을 때는 이미 캐시된 응답(이전 파일)을 제공할 수 있다는 이야기인 것 같았다.


그런데 CloudFront가 뭘까?



해결 방법 찾기

CloudFront의 기본 Cache 수명은 24시간으로 설정되어 있기 때문에, 웹 서버(origin)에서 변경 사항이 발생해도 CloudFront 서버는 바로 반영하지 못한다.

그럼 캐시 설정을 커스터마이징 해주면 되지 않을까?
(만약 캐시 커스터마이징 설정하려면 이거 한번 읽어보기)

그러나 나의 경우엔 이미지를 수정했을 때마다 즉각적으로 반영해야하므로 캐시 커스터마이징 설정으로 해결할 수 없을 것 같았다.

즉, 이 현상을 해결하는 방법은 기본적으로 중간 서버 역할을 하는 CloudFront에 업데이트된 AmazonS3 콘텐츠를 푸시하는 것이었다.

이때 공식 문서에서 제시하는 방법은 2가지였다.
'캐시 무효화 또는 객체 버전 관리'

1. Amazon S3 객체 무효화
Amazon S3 객체를 무효화하여 CloudFront 배포의 캐시에서 해당 객체를 제거할 수 있습니다. 캐시에서 객체가 제거되면 다음 요청 시 Amazon S3에서 직접 객체를 검색합니다.

유의 사항

(1) 응답을 다양화하도록 쿠키나 헤더를 사용하는 객체의 특정 버전은 무효화할 수 없습니다. 이 경우 CloudFront는 객체의 모든 버전을 무효화합니다.
(2) 각 AWS 계정에서는 매달 1,000건의 무료 무효화 경로가 허용됩니다. 매월 1,000건이 넘는 무효화 경로에 대한 요금은 Amazon CloudFront 요금의 무효화 요청을 참조하십시오.

2. 객체 버전 관리를 사용
콘텐츠를 자주 업데이트하는 경우 객체 버전 관리를 사용하여 CloudFront 배포의 캐시를 지우는 것이 모범 사례입니다.

유의사항

(1) 새 버전의 객체를 오리진(Amazon S3)에 저장하면 이전 이름으로 계속 사용할 수 있는 이전 버전의 변경 사항을 되돌릴 수 있습니다. 하지만 여러 버전의 객체를 저장하면 스토리지 비용이 증가할 수 있습니다.
(2) 오리진에서 객체를 업데이트하지만 쿼리 문자열을 기준으로 캐싱하면 스토리지 비용을 절감할 수 있습니다. 하지만 롤백을 준비하려면 이전 객체 버전을 오프라인으로 유지하는 것이 좋습니다.

하지만 위에 서술된 것처럼 각기 장단점이 있어서, 상황에 맞는 방법을 택해야 할 듯하다.
여기서 나는 객체 버전 관리는 선택지에서 제외하고, 캐시 무효화에 대해 알아보기 시작했다.
(왜냐하면 회사에서 객체 버전 관리를 쓰지 않기 때문..)


1. 캐시 무효화

즉 평소에는 static 파일들을 추가할테니 aws에서 기본적값으로 제공하는 캐시 설정을 사용해도 문제가 없지만, hotfix와 같이 배포된 이미지 파일의 구문이 잘못되어 급히 변경해야 되는 상황 같은 경우, Invalidation 기능을 사용하는 것 같았다.

나의 경우엔 일회성이 아니라, 이미지를 수정했을 때마다 즉각적으로 반영해야했다.
그렇다고 수정할 때마다 일일이 캐시 무효화를 해줄 수도 없는 노릇이고...

뭔가 방법이 없을까?



✔ 2. AWS Lambda를 사용한 CloudFront 무효화 자동화 설정하기 (해결!)

AWS Lambda를 사용한 CloudFront 무효화 자동화 설정하기

매번 새로운 콘텐츠가 바뀔 때마다 AWS에 로그인하여 Invalidation을 실행하기에는 너무 레거시한 방법이라고 생각했다. 그리고 AWS Lambda에 S3 Bucket에 Object Created Trigger 이벤트를 등록하여 자동화를 만들 예정이다.

이거다!!!!!!!!!!!!!!!!!!!!!!!!
내가 고민한 것과 정확히 일치하는, 진짜 감사한 글을 발견했다.


바로 적용해볼까 했지만, 일단 이 방법을 쓰는 게 적합한지 검토를 한번 받아야할 것 같아서 (쫄보 신입) 아직 적용해보지 않았다.

만약 적용하게 되면 후기를 이어서 쓰도록 하겠다.



profile
모종삽에서 포크레인까지

0개의 댓글