S3는 대학생 때 처음 개발을 공부하던 때부터 클라우드 분야에서 일하고 있는 현재까지도 항상 편리하게 사용해온 AWS 서비스이다. 사실상 거의 무한에 가까운 양의 데이터를 저장할 수 있고, 가용성도 일레븐 나인(99.999999999%)을 제공하기 때문에 많은 회사들에서도 대량의 데이터를 저장할 때 많이 사용하는 것으로 보인다.
스타트업에서 일할 때 대량의 데이터를 읽어오면서 버킷 내 파일 개수가 늘어날 수록 성능이 점점 느려지는 것 같다는 느낌적인 느낌을 받곤 했는데, 최근 파티셔닝(Partitioning) 이라는 개념을 접하게 되면서 S3 성능을 개선하는 방법에 대해 공부하고 포스팅을 쓰게 되었다.
이 포스팅에서는 S3 파티셔닝을 이용해 어떻게 성능을 올릴 수 있을지에 대해 짧게 정리해볼 예정이다.
(출처: AWS S3 모범사례 공식 문서 / AWS Athena 공식 문서)
S3 파티셔닝이란 무엇일까?
S3가 디렉터리 구조 (또는 '접두사')를 이용해 버킷 내의 데이터를 분산해 구성하는 작업을 의미한다.
즉 S3 내부에서는 자동으로 디렉터리 구조나 prefix(접두사)를 이용해서 파일을 쉽게 찾을 수 있도록 분류해둔다고 하는데, 만약 대량의 데이터를 잘못 파티셔닝 할 경우 성능의 저하가 발생할 수 있다. 예를 들어 같은 폴더에 속한 파일 수가 너무 많아 파티셔닝이 너무 많아지는 경우에는 오버헤드가 발생해 성능 저하를 가져올 수 있고, 반대로 파티션이 너무 적으면 쿼리에서 더 많은 데이터를 스캔해야 하는 문제가 발생하기도 한다.
만약 S3 버킷에 초당 100회 이상의 POST/PUT/DELETE 요청을 하거나 300회 이상의 GET 요청을 해야 한다면, 버킷 내의 데이터를 적절하게 파티셔닝, 즉 분산할 수 있는 방법을 고려해야 한다.
예시를 통해 알아보자. User_id 별로 쌓이는 음성 데이터를 날짜별로 저장해야 한다고 할 때, 아래 2개의 방법 중 어떤 식으로 폴더 구조를 가져가는 게 좋을까?
방법 1.
20240204/USER01/recording.mp3
20240204/USER02/recording.mp3
20240204/USER03/recording.mp3
20240204/USER04/recording.mp3
20240204/USER05/recording.mp3
방법 2.
USER01/20240204/recording.mp3
USER02/20240204/recording.mp3
USER03/20240204/recording.mp3
USER04/20240204/recording.mp3
USER05/20240204/recording.mp3
정답은 2번이다.
1번처럼 데이터를 20240204/ 라는 중복되는 값으로 폴더를 묶을 경우, 모든 파일이 20240204/ 라는 동일 파티션에 저장되는데 이런 데이터가 수만개 이상으로 많아진다면 버킷 성능에 좋지 않은 영향을 주게 될 것이다. 즉, '20240204'라는 파티션 키에 너무 많은 데이터가 들어가있기 때문에, 성능 저하를 가져올 수 있는 것이다.
이 경우 2번 방법처럼 USER_ID를 기준으로 폴더를 애초에 분산함으로써 적은 데이터만 스캔할 수 있게 한다면 파티셔닝되는 데이터 양이 줄어들어 읽기/쓰기 성능을 올릴 수 있다.
이와 같이 파티션 키는 "쿼리에 자주 사용되고 중복되지 않는 유니크한 값" (e.g. UserID)을 사용하는 것이 좋다.
또 다른 방법으로는 키 이름에 Hash를 이용해 무작위 Prefix를 추가하는 방법이 있다.
위의 방법은 처음 버킷을 구성할 때 고려하기에 좋은 방법이지만, 이미 1번 방법으로 구성되어 있는 버킷을 2번처럼 폴더 구조를 한 번에 갈아엎기는 쉽지 않을 것이다.
위 방법 1 데이터의 폴더 구조를 바꾸지 않으면서 성능을 올릴 수 있는 방법으로, 20240204/ 라는 파티션 키 값에 Prefix를 붙여 데이터를 분산시키는 방법이 있다. 아래와 같은 형태로 추가를 할 수 있을 것이다.
11a820240204/USER01/recording.mp3
b81a20240204/USER02/recording.mp3
9a2d20240204/USER03/recording.mp3
c3dd20240204/USER04/recording.mp3
7a9220240204/USER05/recording.mp3
S3가 기본적으로 초당 100회의 요청 처리, 파티션별 2500만 개의 객체 저장 업무를 수행할 수 있으므로 실제로는 2~3개의 프리픽스 문자열로도 충분하다고 한다.
같은 원리로, Prefix 시작지점에 Entropy 값을 넣어 새로운 디렉터리를 묶어주는 방법도 가능하다.
1/20240204/USER01/recording1.mp3
1/20240204/USER02/recording1.mp3
2/20240204/USER03/recording2.mp3
2/20240204/USER04/recording2.mp3
2/20240204/USER05/recording2.mp3
위와 같이 폴더로 들어갔을 때 파일이 1, 2 로 분류될 수 있는 구조라면, prefix 시작 전에 1/ 2/ 로 폴더를 분산시켜주면 훨씬 파티셔닝 성능이 개선될 것이다.
꼭 이러한 규칙이 없는 파일이라도 위에서 무작위 prefix를 넣어줬던 것처럼 무작위 숫자로 폴더를 묶어주어도 성능 개선을 이뤄낼 수 있을 것이다. (e.g. 1f/, 2d/, ...)
이처럼 이번 포스팅에서는 파티셔닝 구조를 잘 이용해 S3 성능 개선을 하는 방법을 아래 3가지로 정리해보았다.
1/ 디렉토리 구조 변경 (Unique하고 자주 사용되는 값으로 폴더 분류 되도록)
2/ 키값에 Random Prefix 값 추가
3/ 특정 규칙이 있는 데이터라면 Prefix 시작지점에 규칙으로 분류하도록 디렉토리 구성
S3에 대량의 데이터를 저장하고 있다면 이 글에서처럼 파티셔닝을 고려해보고, 더 나아가 적절한 S3 Storage class 선택으로 비용 최적화를 하는 것도 좋겠다. 끝