아키텍쳐/Cloud

AWS S3 활용 및 단점 분석

gnidoc 2022. 2. 4. 20:21
반응형

S3란?

S3 로고

S3란 확장성과 데이터 가용성 및 보안과 성능을 제공하는 객체 스토리지 서비스입니다
쉽게 말하자면 Goole One, iCloud와 같은 파일 저장 서비스인데
아래처럼 bucket(버킷)이라는 폴더에 Object(객체)인 파일을 저장할 수 있습니다

aws-ppt란 버킷을 생성 / sample이라는 하위 폴더(prefix)를 생성 / tenor.git라는 파일을 업로드(저장)

추가적으로 위의 예시에서 하위 폴더 역할을 하는 sample은 prefix라고 합니다
실제로 폴더 역할을 하는게 아니고 단순히 하나의 경로 역할만 하고 하나의 객체는 복수개의 prefix로 구성될 수 있어서
S3에서 객체의 경로는 아래와 같이 표현됩니다

s3://{버킷명}/{prefix}/{객체명}

ex)
s3://bucket1/file1.jpg
s3://bucket2/prefix1/file1.jpg
s3://bucket2/prefix1/prefix2/file2.jpg

그리고 위의 예시에서 업로드한 tenor.gif 객체를 보면
업로드한 객체를 다시 다운로드할 수 있고
객체 URL을 통해서 다운로드하지 않고 웹에서 직접 해당 파일을 바로 볼 수 있습니다
(물론 기본적으로 public하게 조회가 불가능하기 때문에 해당 URL로 웹에서 보기 위해선 권한 조정이 필요합니다)

그리고 기본적인 권한관리도 제공해주기 때문에
중요한 파일은 숨기고 일부 객체만 공개하거나
https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/acl-overview.html
인증된 유저에게만 특정 객체에 대해서 공개하는 등의 세부적인 권한 관리도 가능합니다
https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/PresignedUrlUploadObject.html

객체 업데이트/삭제 방식

보통 이름이 같은 파일을 같은 폴더 내에 생성, 복사한다면 기존 파일에 대해서 새로운 파일이 Overwrite(덮어쓰기)되는데
S3도 이와 같은 방식으로 동일한 파일명에 대해서는 Overwrite되는것처럼 처리하지만
생각하는것처럼 실제로 Overwrite가 되지 않고 아래와 같이 해당 파일 객체에 대해서 routing만 다르게 동작합니다

A`는 삭제되고 해당 파일명은 A`로 라우팅됨


즉, 실제 파일을 Overwrite하지 않고 구버전 파일은 삭제를 진행하고 새로 생성된 객체로 routing만 바꿔줍니다
이런 원리로 인해서 제공할 수 있는 기능(=Versioning)이 있는데 이는 뒤에서 후술하겠습니다

그리고 삭제도 콘솔/명령어를 통해서 실행하여도 실제로 바로 삭제가 진행되지 않습니다
즉, 삭제 프로세스가 비동기식으로 동작한다는 의미이고 삭제 명령 후 실제로 객체가 삭제되기까지는 일정시간이 필요합니다
보통은 용량이 큰 객체일수록 실제로 S3에서 삭제되기까지 필요한 시간이 더 길어질 수 있습니다

 

S3 활용

  1. 반복적인 배포가 필요한 경우
    반복적으로 사용하는 보안솔루션, 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

  2. 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 하는 예시


  3. Athena, Glue, Redshift
    S3를 base로 동작하는 데이터베이스 서비스도 존재합니다
    정해진 파일 포맷에 맞춰서 S3로 업로드하면 이를 athena, redshift에서 즉시 조회가 가능하며
    Glue를 사용하면 ETL 작업도 별도의 서버없이 S3에 파일을 업로드만 해도 ETL 작업을 할 수 있습니다
    즉, hadoop과 같은 분산 파일시스템을 직접 구축/운영할 필요없이 S3를 사용한다면 serverless 형태로 운영할 수 있습니다
    S3를 사용하여 데이터 웨어하우스 만들기 -https://www.megazone.com/techblog_180227_redshift/
  4. Cloudfront
    Cloudfront는 AWS에서 제공해주는 CDN(Content Delivery/Distribution Network) 서비스입니다
    Cloudfront는 동영상을 streaming으로 제공 가능하고 이미지와 같은 정적파일(static file) 또한 제공할 수 있는데
    제공할 파일은 S3에 업로드된 객체(콘텐츠)로 사용할 수 있습니다
    예를 들어서 유저가 S3에 파일을 올리기만 한다면 Cloudfront는 S3에 업로드된 객체를 delivery해준다는것입니다
    (S3의 객체 URL 기능과 cloudfront 의 CDN 역할은 다르긴 하지만 이건 나중에 다른 글에서 다루도록 하겠습니다)
    유저는 S3에 직접 접근하지 않고 Cloudfront에 캐싱된 컨텐츠를 사용함


  5. Static Web Page
    많은 스타트업들이 비용을 절감하기 위해서 사용하는 기능 중 하나가 바로 S3 static web hosting 입니다
    보통 S3 단독으로 사용하지 않고 cloudfront와 함께 사용하는데
    S3에 html 파일을 올려두고 static web hosting 기능을 ON하면
    객체 URL로 접속시 일반적인 웹서비스처럼 해당 html을 통해서 frontend 서비스를 제공할 수 있습니다
    VueJS, ReactJS와 같은 SPA(Single Page Application)을 해당 기능을 통해서 서비스 가능하여
    EC2와 같은 별도의 웹서버없이 serverless 하게 운영 가능합니다
    아래 글을 통해서 실습도 해볼 수 있습니다
    https://aws.amazon.com/ko/getting-started/projects/build-serverless-web-app-lambda-apigateway-s3-dynamodb-cognito/module-1/

  6. Network Drive
    Google One, iCloud처럼 클라우드 스토리지처럼 사용 가능합니다
    물론 aws sdk를 직접 사용하는건 사용성이 떨어지기 때문에
    이를 좀 더 편리하게 제공해주는 open source 중 하나를 직접 설치하여 사용할 수 있습니다
    그 중 추천하자면 s3cmd, cloudserver가 있습니다
    https://github.com/s3tools/s3cmd
    https://www.zenko.io/cloudserver/

  7. 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일 후 파일 삭제와 같은 부분도 해당 기능을 통해서 구현할 수 있습니다
    민증 사본처럼 중요한 개인정보 안지우고 있다가 걸리면 벌금이...


  8. Versioning

    위에서 언급했던 객체 업데이트 방식으로 인해서 실제 파일을 Overwrite하지 않고
    내부적으로 routing만 바꾸기 때문에 제공할 수 있는 기능인 버전 관리 기능입니다
    근데 버전 관리하면 떠오르는 git이 있는데
    github처럼 s3를 git server처럼 쓰는 open source도 있습니다
    https://github.com/s3git/s3git

    그리고 s3 version 관리 원리(flow)가 궁금하시다면 아래 문서를 참고하시면 됩니다
    https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/versioning-workflows.html#versioning-workflows-examples

  9.  기본적으로 제공되는 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와 연계한다면 다양하게 사용할 수 있습니다

하지만 아래와 같이 치명적인 단점들도 존재합니다

  1. 제한(Restriction & Limit)
    S3는 간단하게 쓰기엔 좋지만 규모가 커지고 복잡해질수록 추후에 운영시에 일부 제한에 걸리게 됩니다
    공식문서로 제공되는 목록은 아래 링크를 참고해주세요
    https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/BucketRestrictions.html

    대충 대표적인 케이스만 언급해보자면
    AWS 계정 1개의 최대 bucket 수는 100~1000개이며
    (기본 100개며 추가 서비스 한도 증가 요청시 최대 1000개 가능)
    prefix에 대해서 읽기 요청은 초당 3500회, 생성/수정/삭제 요청은 초당 5500회만 가능합니다

    문제는 이런 요청 최대 제한은 내부적으로 알아서 Scaling되며 사용자(개발자)는 수치적으로 정확하게 알 수 없습니다
    즉, 실제로 특정 객체에 대해서 읽기 요청을 초당 3500회 수행할 정도의 성능이 나오려면 일정 시간이 필요하다는 뜻입니다
    그리고 bucket 이름은 재사용이 가능하나 AWS 전체 계정에서 unique해야하여
    타 계정에서 해당 이름을 사용하고 있다면 사용이 불가능합니다
    따라서 서비스가 이미 상용으로 올라간 상태라면 되도록이면 bucket을 삭제하지 않는 것이 좋습니다

  2. 설계의 중요성
    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라곤 하지만 되도록이면 애초에 작게 나누는게...)

  3. 안정적인 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하는 애플리케이션을 사용하는게 좋습니다

  4. 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주소를 확인할 필요가 있을 수 있습니다
    서버리스라매!!!!


  5. 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로 구축된 서비스는 자주 죽어서 재시작되어 캐시가 삭제/갱신됩니다... ㅎㅎ
    (사실 이런 저런 이유 때문에라도 가끔씩 인스턴스를 재부팅해주는게 좋긴합니다)

    관련된 내용 또한 AWS 문서에서 다뤄주고 있습니다
    https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/UsingRouting.html

  6. Class 문제점
    주로 Glacier를 사용하다가 발생하는 문제가 많습니다
    (Glacier란? https://aws.amazon.com/ko/s3/storage-classes/glacier/)

    사실 문제점이라기보단 설계 문제이긴 하지만
    비용 절감한다고 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시간 이상 걸릴 수 있습니다
    (찾는 데이터가 없으면 더 난감하겠죠 ^^)

  7. 비용
    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/

 

Amazon S3 SLA

본건 Amazon S3 서비스 수준 계약(“본건 SLA”)은 Amazon Web Services, Inc.(“AWS”) 및 그 계열사와 AWS 서비스 사용자(“고객”) 간에 체결된 Amazon Web Services 이용계약(“AWS 계약”)의 조건에 따른 Amazon Sim

aws.amazon.com

또한 자체적으로 cloud storage를 구축하기보단 S3를 사용하는게 리소스관리 측면에서는 효율적이나
비용적인 측면에서는 자체적으로 구축하는게 저렴할 수 있습니다
(물론 개발/운영할 인건비까지 생각하면 S3 쓰는게...)

따라서 S3가 정답은 아니나 충분히 고려해볼만한 서비스이니 많은 참고바랍니다

반응형