Foundry
파일 업로드 시스템 설계
중급
핵심

멀티파트와 청크 업로드

파일을 쪼개면 재시도 단위가 작아진다

큰 파일은 한 번의 요청으로 올리지 않습니다. 파트로 쪼개 각각 올리고 스토리지가 합칩니다. 얻는 것은 둘입니다. 병렬 업로드로 대역폭을 채우고, 재시도 단위가 파일 전체에서 파트 하나로 줄어듭니다.

파일을 파트로 나눠 병렬로 업로드하고 스토리지가 하나로 합친다 파일 50GB 파트로 나눈다 파트 1 파트 2 파트 3 파트 4 동시에 스토리지 합쳐서 한 객체

왜 쪼개야 하나

단일 요청에는 크기 상한이 있습니다. 상한을 넘기면 방법이 없어서 쪼개는 것이 선택이 아니라 필수가 됩니다.

상한 아래여도 쪼개는 이유가 재시도입니다. 50GB 를 올리다 98퍼센트에서 끊기면 처음부터 다시 올립니다. 10MB 파트로 나눴다면 그 파트 하나만 다시 보냅니다.

방식실패 시 다시 보낼 양
단일 요청 50GB50GB 전체
10MB 파트로 나눔10MB

파트 크기를 정하는 상충

파트를 작게 하면 재시도가 싸지고, 크게 하면 요청 수가 줄어듭니다. 양쪽 다 좋게 할 수는 없습니다.

파트 크기좋아지는 것나빠지는 것
작다재시도 비용, 진행률 정밀도요청 수와 왕복 오버헤드가 늘어난다
크다요청 수가 줄고 처리량이 오른다실패 시 다시 보낼 양이 커진다

여기에 제약이 하나 더 붙습니다. 파트 개수에도 상한이 있어서, 파일이 클수록 파트를 작게 둘 수 없습니다. 50GB 를 5MB 파트로 나누면 10,000개가 되는데 상한이 그보다 낮으면 파트를 키워야 합니다. 그래서 파트 크기는 고정값이 아니라 파일 크기에서 계산하는 값입니다.

정리하지 않으면 돈이 나간다

파트를 몇 개 올리다 중단하면 그 파트들이 스토리지에 남습니다. 합치기를 완료하지 않았으니 객체는 없는데 미완성 업로드로 조각이 쌓이고, 조각도 저장 요금을 냅니다.

목록에 안 보이는 것이 함정입니다. 객체 목록을 조회해도 나오지 않아서, 요금이 오르기 전까지 아무도 모릅니다. 그래서 일정 기간 지난 미완성 업로드를 자동으로 지우는 규칙을 처음부터 걸어 둡니다.

병렬은 무조건 이득이 아니다

파트를 동시에 올리면 대역폭을 채울 수 있습니다. 다만 동시 개수를 무한히 늘리면 클라이언트 쪽에서 경합이 생기고 모바일에서는 배터리와 발열이 문제가 됩니다. 동시 개수는 보통 몇 개로 제한하고, 실패한 파트만 다시 큐에 넣습니다.

면접에서 이렇게 나옵니다

Q.큰 파일을 멀티파트로 나눠 올리는 이유는 무엇인가요

두 가지입니다. 재시도 단위를 줄이고 병렬로 올려 대역폭을 채웁니다.

단일 요청에는 크기 상한이 있어서 큰 파일은 쪼개는 것이 필수입니다. 상한 아래여도 쪼개는 이유는 실패 비용입니다.

방식98퍼센트에서 끊기면
단일 요청 50GB50GB 를 처음부터 다시
10MB 파트10MB 만 다시

모바일에서 연결이 끊기는 것은 예외가 아니라 정상 상황이므로, 재시도 단위가 작다는 것이 그대로 완주율이 됩니다.

흔한 실수: 멀티파트를 속도 향상 기법으로만 설명하는 것. 병렬 업로드로 빨라지는 것도 맞지만, 실무에서 더 중요한 이득은 실패했을 때 다시 보낼 양입니다. 대역폭이 좁으면 병렬로도 빨라지지 않지만 재시도 이득은 그대로 남습니다.

Q.파트 크기는 어떻게 정하나요

파일 크기에서 계산합니다. 고정값으로 둘 수 없습니다.

상충이 있습니다. 작게 하면 재시도가 싸지지만 요청 수와 왕복 오버헤드가 늘고, 크게 하면 요청 수가 줄지만 실패 시 다시 보낼 양이 커집니다.

여기에 파트 개수 상한이 겹칩니다. 50GB 를 5MB 로 나누면 10,000개가 되는데 상한이 그보다 낮으면 파트를 키워야 합니다.

파트 크기 = max(최소 파트 크기, 파일 크기 / 파트 개수 상한)

그래서 작은 파일은 최소 크기로, 큰 파일은 개수 상한에 맞춰 커집니다.

흔한 실수: 파트 크기를 상수로 박는 것. 그러면 어느 파일 크기에서 개수 상한을 넘어 업로드가 실패하는데, 테스트 파일이 작으면 그 경계를 만나지 못해 운영에서 터집니다.

Q.업로드를 중간에 그만두면 무슨 일이 남나요

올린 파트들이 미완성 업로드로 스토리지에 남고 저장 요금을 냅니다.

합치기를 완료하지 않았으므로 최종 객체는 만들어지지 않습니다. 그런데 파트는 이미 저장돼 있습니다. 문제는 이 조각이 객체 목록에 보이지 않는다는 것입니다.

확인 방법미완성 파트가 보이나
객체 목록 조회안 보인다
미완성 업로드 목록 조회보인다
요금 청구서보인다

사용자가 앱을 닫거나 네트워크가 끊기는 것은 흔한 일이라 조각이 계속 쌓입니다. 그래서 일정 기간 지난 미완성 업로드를 자동으로 지우는 규칙을 처음부터 걸어 둡니다.

흔한 실수: 업로드가 실패했으니 아무것도 안 남았다고 답하는 것. 실패 시점에 이미 올라간 파트는 남아 있고, 지우는 쪽은 우리가 설정해야 합니다.

Q.파트를 병렬로 올릴 때 동시 개수는 무엇을 보고 정하나요

클라이언트 쪽 한계를 봅니다. 무한히 늘리면 오히려 느려집니다.

동시 개수결과
1대역폭을 못 채운다. 왕복 대기가 그대로 노출된다
몇 개대역폭을 채우면서 경합이 적다
수십 개연결 경합, 모바일에서 배터리와 발열, 메모리 압박

브라우저는 호스트당 동시 연결 수에 제한이 있어서, 그 이상 늘려도 큐에서 기다립니다. 모바일은 여기에 배터리와 발열 제약이 더해집니다.

실패한 파트만 다시 큐에 넣는 구조로 만들면, 동시 개수를 적게 유지해도 전체 완주율이 떨어지지 않습니다.

흔한 실수: 파트를 전부 동시에 던지는 것. 파트가 500개면 요청 500개를 한 번에 만드는 셈이고, 대부분이 대기하면서 메모리만 점유합니다.

먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.

읽었으면 문제로 확인해보세요

파일 업로드 시스템 설계 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.