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

중복 제거와 콘텐츠 해시

같은 내용은 한 번만 저장한다. 지울 때가 어렵다

팀 공유 서비스에서는 같은 파일이 여러 번 올라옵니다. 내용이 같으면 콘텐츠 해시가 같으므로, 실제 바이트는 한 벌만 두고 참조만 늘립니다. 하루 40TB 중 상당량이 이렇게 줄어듭니다.

같은 내용이면 해시가 같으므로 실제 바이트는 한 벌만 두고 참조만 늘린다 사용자 A 사용자 B 같은 파일을 올린다 해시가 같다 바이트 한 벌 참조 2개 저장은 한 번, 참조만 늘린다 둘 중 하나가 지워도 바이트는 남아야 한다

해시를 누가 계산하나

클라이언트가 계산해 보내면 업로드를 아예 건너뛸 수 있습니다. 이미 있는 해시면 바이트를 보내지 않고 참조만 추가합니다. 전송량이 0이 됩니다.

그런데 여기 신뢰 경계가 있습니다. 클라이언트가 보낸 해시를 그대로 믿으면 문제가 생깁니다.

위험무슨 일이 벌어지나
남의 파일 해시를 추측해 보낸다올리지도 않은 파일에 접근 권한을 얻는다
내용과 다른 해시를 보낸다저장된 바이트와 기록이 어긋난다

첫 번째가 실제 취약점입니다. 그래서 해시만으로 접근을 주지 않습니다. 해시는 저장을 줄이는 데 쓰고, 그 파일을 볼 권한은 별도로 확인합니다. 업로드를 건너뛰게 해주려면 최소한 파일 크기를 함께 확인하거나, 무작위 일부 구간을 보내게 해 실제로 가진 것을 증명시킵니다.

지우는 것이 어려운 이유

바이트 한 벌을 여러 참조가 가리키므로, 한 사람이 지웠다고 바이트를 지우면 남의 파일이 사라집니다.

그래서 참조 카운트를 둡니다. 참조가 0이 될 때만 바이트를 지웁니다. 다만 카운트를 정확히 유지하는 것이 쉽지 않습니다. 동시에 올리고 지우면 카운트가 어긋나고, 어긋난 방향에 따라 결과가 다릅니다.

어긋난 방향결과
실제보다 크게 세었다아무도 안 쓰는 바이트가 영구히 남는다. 요금만
실제보다 작게 세었다쓰는 사람이 있는데 지워진다. 데이터 손실

두 번째가 훨씬 나쁩니다. 그래서 카운트가 의심스러우면 지우지 않는 쪽으로 기울입니다. 즉시 삭제 대신 유예 기간을 두고, 그 사이 참조가 다시 생기면 취소합니다.

중복 제거를 안 하는 선택도 있다

참조 카운트와 유예 삭제를 만드는 비용이 절감보다 클 수 있습니다. 파일이 대부분 고유하다면 중복 제거로 줄어드는 양이 적습니다. 먼저 재볼 것은 실제 중복률이고, 낮으면 하지 않는 편이 낫습니다.

면접에서 이렇게 나옵니다

Q.파일 중복 제거를 어떻게 구현하나요

내용의 해시를 키로 삼아 같은 내용이면 바이트를 한 벌만 둡니다.

업로드된 내용의 해시를 계산한다
그 해시가 이미 있으면 바이트를 저장하지 않는다
사용자의 파일 레코드는 그 바이트를 가리키는 참조로 만든다

이것을 콘텐츠 주소 지정이라고 합니다. 파일 이름이나 경로가 아니라 내용이 위치를 정합니다. 이름이 달라도 내용이 같으면 같은 바이트를 씁니다.

흔한 실수: 파일명과 크기로 중복을 판단하는 것. 이름이 같고 내용이 다른 경우와 이름이 다르고 내용이 같은 경우를 둘 다 틀립니다. 판단 기준은 내용이어야 하고, 그래서 해시를 씁니다.

Q.클라이언트가 계산한 해시를 그대로 믿어도 되나요

안 됩니다. 여기에 신뢰 경계가 있습니다.

클라이언트 해시를 믿으면 업로드를 건너뛸 수 있어 전송량이 0이 됩니다. 매력적이지만 위험이 따라옵니다.

위험결과
남의 파일 해시를 보낸다올리지도 않은 파일에 접근 권한을 얻는다
내용과 다른 해시를 보낸다저장된 바이트와 기록이 어긋난다

첫 번째가 실제 취약점입니다. 그래서 해시만으로 접근을 주지 않습니다. 해시는 저장을 줄이는 데 쓰고, 볼 권한은 따로 확인합니다.

업로드를 건너뛰게 해주려면 실제로 가졌음을 증명시킵니다. 파일 크기를 함께 확인하거나 무작위 일부 구간을 보내게 하는 방식입니다.

흔한 실수: 해시가 일치하면 그 파일을 이미 가진 것으로 보는 것. 해시는 공개된 값처럼 다뤄야 합니다. 아는 것과 가진 것은 다릅니다.

Q.중복 제거한 파일을 한 사용자가 지우면 어떻게 처리하나요

바이트를 바로 지우면 남의 파일이 사라집니다. 여러 참조가 같은 바이트를 가리키기 때문입니다.

그래서 참조 카운트를 두고 0이 될 때만 바이트를 지웁니다. 문제는 카운트를 정확히 유지하는 것이 쉽지 않다는 점입니다. 동시에 올리고 지우면 어긋납니다.

어긋난 방향결과
실제보다 크게 세었다아무도 안 쓰는 바이트가 남는다. 요금만
실제보다 작게 세었다쓰는 사람이 있는데 지워진다. 데이터 손실

두 번째가 훨씬 나쁩니다. 그래서 지우지 않는 쪽으로 기울입니다. 즉시 삭제 대신 유예 기간을 두고, 그 사이 참조가 다시 생기면 취소합니다.

흔한 실수: 두 실패를 같은 무게로 다루는 것. 요금이 새는 것과 남의 데이터가 사라지는 것은 복구 가능성이 다릅니다. 한쪽은 청구서로 드러나고 한쪽은 되돌릴 수 없습니다.

Q.중복 제거를 하지 않는 선택은 언제 맞나요

실제 중복률이 낮을 때입니다. 먼저 재보고 결정합니다.

중복 제거는 공짜가 아닙니다. 참조 카운트, 유예 삭제, 카운트 어긋남 복구를 만들어야 하고, 그 코드가 데이터 손실을 낼 수 있는 자리에 놓입니다.

상황판단
팀이 같은 문서를 공유한다중복률이 높다. 절감이 크다
사용자마다 고유한 사진과 영상중복률이 낮다. 비용만 남는다

파일 크기 분포도 봅니다. 큰 파일 몇 개가 중복이면 절감이 크고, 작은 파일 수천 개가 중복이면 해시 계산과 조회 비용이 절감을 잠식합니다.

흔한 실수: 저장 비용 절감을 이유로 무조건 도입하는 것. 절감량을 재지 않고 넣으면 복잡도만 늘고 요금은 그대로입니다. 중복률은 샘플로 며칠만 재봐도 나옵니다.

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

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

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