그리고 위의 예시에서 업로드한 tenor.gif 객체를 보면 업로드한 객체를 다시 다운로드할 수 있고 객체 URL을 통해서 다운로드하지 않고 웹에서 직접 해당 파일을 바로 볼 수 있습니다 (물론 기본적으로 public하게 조회가 불가능하기 때문에 해당 URL로 웹에서 보기 위해선 권한 조정이 필요합니다)
보통 이름이 같은 파일을 같은 폴더 내에 생성, 복사한다면 기존 파일에 대해서 새로운 파일이 Overwrite(덮어쓰기)되는데 S3도 이와 같은 방식으로 동일한 파일명에 대해서는 Overwrite되는것처럼 처리하지만 생각하는것처럼 실제로 Overwrite가 되지 않고 아래와 같이 해당 파일 객체에 대해서 routing만 다르게 동작합니다
A`는 삭제되고 해당 파일명은 A`로 라우팅됨
즉, 실제 파일을 Overwrite하지 않고 구버전 파일은 삭제를 진행하고 새로 생성된 객체로 routing만 바꿔줍니다 이런 원리로 인해서 제공할 수 있는 기능(=Versioning)이 있는데 이는 뒤에서 후술하겠습니다
그리고 삭제도 콘솔/명령어를 통해서 실행하여도 실제로 바로 삭제가 진행되지 않습니다 즉, 삭제 프로세스가 비동기식으로 동작한다는 의미이고 삭제 명령 후 실제로 객체가 삭제되기까지는 일정시간이 필요합니다 보통은 용량이 큰 객체일수록 실제로 S3에서 삭제되기까지 필요한 시간이 더 길어질 수 있습니다
S3 활용
반복적인 배포가 필요한 경우 반복적으로 사용하는 보안솔루션, agent 와 같이 반복적인 배포가 필요한때 사용하면 좋습니다 S3에 배포가 필요한 파일을 업로드해두고 해당 객체가 필요한 EC2(IAM User/Role)에 GetObject 권한을 부여하면 별도의 네트워크 작업 없이 EC2에서 aws sdk를 통해 다운로드가 가능합니다 On-premise에서 이런 방식을 제공하려면 다운로드를 위한 client 개발과 네트워크, 방화벽 등의 작업이 필요하고 별도의 솔루션을 구매할 경우엔 라이센스 비용이 별도로 발생하거나 vendor lock-in으로 인해 추후에 migration이 매우 복잡해질 수 있습니다 하지만 S3는 이런 interface나 sdk를 모두 제공하고 있기 때문에 개발할 수 있는 시간을 줄일 수 있습니다 추가적으로 open source 중에서 s3를 disk처럼 mount해서 사용할 수 있게 해주는 라이브러리도 있습니다 (개인적으로 awscli면 충분하다고 생각하여 비추천하지만 은근히 쓰는 분들이 있네요) https://github.com/tongwang/s3fs-c
Data Export/Import AWS 내의 서비스인 DMS(Data Migration Service), Cloud Watch에서 데이터를 export 해야되는 경우에 S3를 사용해야됩니다 GB~TB정도 되는 대용량 파일에 대해서도 S3는 안정적으로 제공하기 때문에 매우 편리합니다 또한 CloudWatch, RDS, Redshift 등의 서비스에 데이터를 import 해야되는 경우에도 S3 사용이 가능합니다 이 뿐 아니라 Elastic Beanstalk, Lambda와 같은 application의 배포도 S3를 통하여 자동 배포를 할 수 있습니다 Data Pipeline으로 Dynamo DB의 데이터를 import/export 하는 예시
Athena, Glue, Redshift S3를 base로 동작하는 데이터베이스 서비스도 존재합니다 정해진 파일 포맷에 맞춰서 S3로 업로드하면 이를 athena, redshift에서 즉시 조회가 가능하며 Glue를 사용하면 ETL 작업도 별도의 서버없이 S3에 파일을 업로드만 해도 ETL 작업을 할 수 있습니다 즉, hadoop과 같은 분산 파일시스템을 직접 구축/운영할 필요없이 S3를 사용한다면 serverless 형태로 운영할 수 있습니다 S3를 사용하여 데이터 웨어하우스 만들기 -https://www.megazone.com/techblog_180227_redshift/
Cloudfront Cloudfront는 AWS에서 제공해주는 CDN(Content Delivery/Distribution Network) 서비스입니다 Cloudfront는 동영상을 streaming으로 제공 가능하고 이미지와 같은 정적파일(static file) 또한 제공할 수 있는데 제공할 파일은 S3에 업로드된 객체(콘텐츠)로 사용할 수 있습니다 예를 들어서 유저가 S3에 파일을 올리기만 한다면 Cloudfront는 S3에 업로드된 객체를 delivery해준다는것입니다 (S3의 객체 URL 기능과 cloudfront 의 CDN 역할은 다르긴 하지만 이건 나중에 다른 글에서 다루도록 하겠습니다) 유저는 S3에 직접 접근하지 않고 Cloudfront에 캐싱된 컨텐츠를 사용함
Archiving & Life Cycle 많이 놓치는 기능 중 하나인데 S3 자체에서 Archiving, life cycle 을 제공하고 있습니다 Archiving은 S3에 객체 업로드 후에 일정 기간이 되면 좀 더 저렴한 storage class 로 변경해주는 기능입니다 (ex- S3 Standard -> S3 Infrequent Access/Glacier Deep Archive) 다만 storage class 에 따라서 기능이 달라지기 때문에 상용에서 해당 기능을 사용한다면 문제가 되는 경우가 있으니 해당 storage class 에 따른 제약사항에 대해서 반드시 파악 및 테스트 후에 사용하는 것을 권장합니다 예를 들어서 게시판의 첨부파일 기능을 S3에 저장되게 구현해두고 비용 절감을 위해서 180일 이후에 Glacier Deep Archive로 변경하는 rule을 지정해놨는데 1년 뒤에 해당 게시글의첨부파일을 다운받아야되는 경우되면 해당 객체에 대해서 Retrieval 과정을 거쳐서 다시 복원한 뒤에 GetObject 가 가능합니다 구현이 복잡한걸 떠나서 Retrieval 자체가 3~5시간 정도 소요되기 때문에 이렇게 해당 storage class 에 대해서 파악하지 않고 사용한다면 매우 큰 문제가 될 수 있습니다
그리고 별도의 batch script 없이 Life cycle 기능을 통해서 일정 기간 후에 자동 삭제도 가능합니다 배포용 파일, 백업용 데이터, 임시파일과 같이 영구적으로 저장할 필요없고 임시로 잠시 S3에 보관해야되는 경우에 매우 유용한데 대부분 까먹고 놔두고 있다가 엄청난 양의 용량이 되면서 비용문제와 함께 대두되면서 해당 객체의 주인을 찾는 여정을 떠나는데 해당 기능을 통해서 자동 삭제가 되게 한다면 이런 운영 문제에 대해서 약간 자유로워질 수 있습니다 다만 휴지통처럼 삭제된 객체 복구가 안되기 때문에 사용에 주의가 필요합니다 이 외에도 주민등록증 인증 후 30일 후 파일 삭제와 같은 부분도 해당 기능을 통해서 구현할 수 있습니다 민증 사본처럼 중요한 개인정보 안지우고 있다가 걸리면 벌금이...
Versioning 위에서 언급했던 객체 업데이트 방식으로 인해서 실제 파일을 Overwrite하지 않고 내부적으로 routing만 바꾸기 때문에 제공할 수 있는 기능인 버전 관리 기능입니다 근데 버전 관리하면 떠오르는 git이 있는데 github처럼 s3를 git server처럼 쓰는 open source도 있습니다 https://github.com/s3git/s3git
기본적으로 제공되는 SDK shell에서는 AWS CLI, python은 boto3 등 AWS에서 자체적으로 제공해주는 강력한 SDK가 존재합니다 이 외에도 C++, Go, JS, PHP 등등 현업에서 주로 사용되는 언어들을 대부분 지원해주며 공식 문서를 통해서 콘솔, CLI, SDK 등에 대해서 모두 사용법을 제시해줍니다 https://aws.amazon.com/ko/tools/
만약에 자체적으로 S3와 같은 Cloud Storage를 개발한다고 했을때 안정성은 둘째치고 이런 문서화와 모든 플랫폼에 대한 지원까지 가능하려면 많은 시간과 비용이 들 것입니다
단점(문제점)
위의 활용 사례만 보면 serverless 하게 storage로 사용할 수 있고 web hosting도 할 수 있고 open source와 연계한다면 다양하게 사용할 수 있습니다
대충 대표적인 케이스만 언급해보자면 AWS 계정 1개의 최대 bucket 수는 100~1000개이며 (기본 100개며 추가 서비스 한도 증가 요청시 최대 1000개 가능) prefix에 대해서 읽기 요청은 초당 3500회, 생성/수정/삭제 요청은 초당 5500회만 가능합니다
문제는 이런 요청 최대 제한은 내부적으로 알아서 Scaling되며 사용자(개발자)는 수치적으로 정확하게 알 수 없습니다 즉, 실제로 특정 객체에 대해서 읽기 요청을 초당 3500회 수행할 정도의 성능이 나오려면 일정 시간이 필요하다는 뜻입니다 그리고 bucket 이름은 재사용이 가능하나 AWS 전체 계정에서 unique해야하여 타 계정에서 해당 이름을 사용하고 있다면 사용이 불가능합니다 따라서 서비스가 이미 상용으로 올라간 상태라면 되도록이면 bucket을 삭제하지 않는 것이 좋습니다
설계의 중요성 1번과 같은 제한 사항으로 인해서 bucket/prefix 의 설계가 중요합니다 특히 잘못된 설계로 인해서 병목현상이 발생하게 된다면 아래와 같은 검색을 하게 되는 경우가 많아집니다 (+직관적으로 알 수 없는 Scaling으로 인해서도 검색해보긴 합니다) 요즘은 이런 문제에 대한 해답도 AWS에서 문서로 제공해줍니다 - https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/optimizing-performance.html
보통은 하나의 버킷에 prefix 없이 다수의 객체를 생성/삭제하면서 아래와 같은 여러 서비스를 연계해서 사용할 경우에 이런 병목현상이 발생하게 되는데 만약 상용 서비스에서 이런 문제가 발생하게 되면 Scaling 이 완료 될때까지 기도하는 수 밖에 없습니다 주로 S3와 연계해서 사용되는 서비스 및 개발자(사용자)
따라서 prefix는 다양하게 depth를 많이 나눌수록 요청을 분산시킬 수 있고 요청이 분산되면 상대적으로 지연시간을 좀 더 낮출 수 있습니다
예를 들면 유저의 프로필 사진을 저장해야된다면 user/123_profile.jpg, user/123_profile_thumbnail.jpg 이렇게 저장하지 않고 user/[user id]/profile.jpg, user/[user id]/thumbnail.jpg 이렇게 유저별로 나누는 식으로 설계를 하면 됩니다 대충 prefix를 쓸수록 좋다 이말입니다
또한 작은 파일은 바로 S3에 업로드/복사해도 되지만 100MiB 이상의 대용량 파일은 멀티파트 업로드를 사용하는걸 권장합니다 (객체 크기는 최대 5TiB라곤 하지만 되도록이면 애초에 작게 나누는게...)
안정적인 client 구현 위에서 언급한 것처럼 Scaling이 완료될때까지 기도하기 위해선 안정적인 client 를 구현해야 됩니다 (Scaling이 완료되기 전엔 503 Server error가 발생할 수 있습니다) 따라서 재처리는 필요가 아닌 필수 방식이고 AWS에서 권장하는 재처리 방식은 백오프 방식입니다 Scaling이 완료되어 성공할때까지 1차는 2초, 2차는 4초, 3차는 6초... 이렇게 재시도할때마다 재시도 시간을 조금씩 늘리는 것입니다 이 또한 공식 문서에서 pseudo코드로 제공하고 있습니다 https://docs.aws.amazon.com/ko_kr/general/latest/gr/api-retries.html
그리고 위에서 언급했던 멀티파트도 클라이언트단에서 고려되야하며 1MiB 미만은 적극적으로 재시도해도 되나 100MiB 이상의 멀티파트 업로드의 경우 병목 걸린 파트 중 가장 느린 일부(1~5%)만 재시도하는 것이 좋습니다 물론 애초에 초리량 자체가 높은 경우엔 Java SDK 중 S3 Transfer Manager처럼 병렬로 GET/PUT하는 애플리케이션을 사용하는게 좋습니다
IP문제(Network) 가끔은 느린 이유가 IP 문제일 수도 있습니다 S3가 serverless한 서비스이긴 하나 이 또한 내부적으로는 서버로 구축되어 있기 때문에 Scaling 중에 확인해보면 요청해던 S3 DNS 의 IP수가 바뀌는걸 볼 수 있습니다 예를 들자면 아래와 같은 상황이 발생할 수 있습니다 * 특정 prefix 에 대량의 put 요청 중(xxx.100~105) => Scaling 발생 * 해당 prefix 에 xxx.106~110이 새로 증설되어 새로운 HTTP Connection 사용 가능 * 이미 진행 중인 요청들은 증설된 connection 을 사용하지 않아서 사용자 입장에선 병목현상이 여전히 발생 중 이런 상황에서 병목이 발생한 prefix에 요청을 하게 된다면 503 Server Error를 겪을 수 있기 때문에 안정적인 client를 구현해야 재처리가 발생하면서 새로운 connection을 사용하게 됩니다
또한 단일IP 사용으로 인한 IP Caching 문제도 많기 때문에 S3와 통신에 쓰이는 IP주소를 확인할 필요가 있을 수 있습니다 서버리스라매!!!!
IP문제(Program Language) 더 큰 문제는 IP문제는 OS Level이 아닌 Program Language Level에서도 발생할 수 있습니다 주로 백엔드(서버) 개발은 Java Application이나 레거시 웹서비스는 PHP를 많이 사용하는데 Java, PHP에서는 이런 문제들이 있습니다 * Java : JVM에서 DNS 조회 결과를 영구 Caching함(InetAddress) * PHP : PHP VM이 재시작될 때까지 DNS 조회 결과를 Caching(getHostByName)
하지만 신기하게도 Python과 Node.js로 구축된 서비스에서는 이런 문제가 자주 발생하지 않는데 이는 DNS Caching이 안되고 App 수준에서 따로 제어되기 때문이며(즉, DNS Caching을 직접 구현해야됨) 결정적으로 Python, Node.js로 구축된 서비스는 자주 죽어서 재시작되어 캐시가 삭제/갱신됩니다... ㅎㅎ (사실 이런 저런 이유 때문에라도 가끔씩 인스턴스를 재부팅해주는게 좋긴합니다)
사실 문제점이라기보단 설계 문제이긴 하지만 비용 절감한다고 Glacier를 도입했다가 낭패보는 일이 생길 수 있습니다
주로 Life cycle을 통해서 Class 을 전환해서 비용 절감하거나 백업용도로 사용하는 경우가 많은데 장점은 S3 내에서 알아서 전환이 되다보니 별도의 작업도 없어서 안정적이고 싸다는 점이지만 단점은 자유도가 떨어져서 마음대로 사용하기가 어렵다는 점입니다 (물론 그에 따른 비용을 더 낸다면 좀 더 자유롭게 사용은 가능합니다) 예를 들어서 S3 내에서 검색하는것도 Glacier를 쓰면 GB당 $0.01를 내야하고 3개월 이전에 삭제시 비용이 발생하고(이후엔 무료) 업로드, 검색에 대한 UI를 제공 안해주거나 아카이빙된 데이터 다운로드시 3~5시간이 소요되는 등 S3의 Storage Class마다 특징이 있기 때문에 Standard Class 외에는 좀 더 깊이 있는 분석과 설계가 필요합니다
예를 들어서 nginx access log를 S3로 export 했다가 S3 Life Cycle을 사용해서 90일 뒤에 Glacier로 전환했더니 갑자기 해킹과 같은 보안문제가 발생하여 해당 log를 꺼내봐야되는 상황이 발생했을때 무슨 log를 봐야하는지 몰라서 검색으로 삽질하다가 검색 비용만 엄청 발생할 수 있고 찾았다고 해도 다운로드받는 시간만 3~12시간 이상 걸릴 수 있습니다 (찾는 데이터가 없으면 더 난감하겠죠 ^^)
비용 iCloud처럼 용량에 대한 비용을 내는건 기본이고 데이터 전송, 요청(PUT, GET, DELETE...)에 대해서도 모두 비용이기 때문에 S3 Standard Class에 PB급의 데이터를 모두 올려서 사용한다면 엄청 큰 비용이 발생합니다 따라서 용도에 맞게 Class를 변경해서 비용관리를 할 필요가 있습니다 https://aws.amazon.com/ko/s3/pricing/
2TB의 데이터를 단순히 S3 Standard Class에 보관만해도 한달에 발생하는 비용은 아래와 같습니다 $0.025 * 2048GB = $51.2 = 한화 약 6만원
iCloud에서 2TB plan이 만원대인걸 생각해보면 매우 비싼 편입니다 iCloud 한국 비용
물론 많이 쓸수록 좀 더 저렴해지긴하는데 그 차이는 크지 않습니다 대기업 아니고서 500TB를 쓸 일이... 아니 그것보다 할인율이 겨우 8%...?
결론?
사실 위의 경우는 다 직접 상용 서비스에서 경험해봤던 이슈들인데 설계시 고려를 못했던 것도 있고 당시엔 고려대상이 아니었다가 운영 중 고려해야되는 상황이 된 경우가 있었습니다 (갑자기 서비스가 잘된다거나 연계하던 서비스가 잘되서 트래픽이 커진 경우...)
제약사항들이 있긴하지만 S3는 여전히 매력적인 서비스이고 기본적으로 제공해주는 AWS SDK도 훌륭하지만 open source도 잘되어있는 편이라 간단한 서비스부터 복잡한 대규모 서비스까지 사용하기 좋습니다 (어떻게 설계하느냐에 따라 다르겠지만...)
또한 SLA상으로 오류가 발생한다면 그에 따른 보상도 해준다니 혹시나 장애가 발생한다면 그에 따른 보상을 받을 수도 있습니다 (그 시간동안 잃어버린 데이터의 가치가 더 크겠지만...) https://aws.amazon.com/ko/s3/sla/