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

재개와 재시도

끊김이 예외가 아니라 정상인 환경에서 설계하기

요구사항에서 모바일이 60퍼센트 입니다. 끊김은 예외가 아니라 정상 상황입니다. 그래서 업로드는 "성공 또는 실패"가 아니라 재개할 수 있는 상태를 가져야 합니다.

재개하려면 상태가 어딘가 있어야 한다

파일을 파트로 쪼갰다면 어느 파트까지 올라갔는지 알아야 이어서 보낼 수 있습니다. 그 상태를 누가 들고 있느냐로 갈립니다.

상태를 두는 곳재개 가능 범위한계
클라이언트 메모리같은 화면에서 일시 중단앱을 닫으면 사라진다
클라이언트 저장소앱을 다시 켜도 이어감기기를 바꾸면 못 이어간다
서버의 업로드 세션어느 기기에서도 이어감세션 정리 정책이 필요하다

스토리지에 물어보는 방법도 있습니다. 이미 올라간 파트 목록을 조회해 빠진 것만 보내는 방식입니다. 이러면 클라이언트가 상태를 안 들고 있어도 됩니다.

재시도는 중복을 만든다

끊김의 절반은 응답을 못 받은 것입니다. 요청이 서버에 닿았는지 알 수 없습니다.

클라이언트가 파트를 보냈다
응답을 받기 전에 연결이 끊겼다
서버는 받았을 수도 있고 못 받았을 수도 있다
클라이언트는 다시 보낸다

파트 업로드는 같은 번호에 덮어쓰므로 두 번 보내도 결과가 같습니다. 문제는 업로드 완료 처리입니다. 완료 요청이 두 번 들어오면 파일이 두 개 만들어지거나 알림이 두 번 갑니다.

그래서 멱등 키를 씁니다. 클라이언트가 업로드를 시작할 때 키를 하나 만들고 완료 요청에 함께 보냅니다. 서버는 같은 키를 이미 처리했으면 새로 만들지 않고 앞의 결과를 돌려줍니다.

재시도 간격을 두는 이유

끊긴 직후 곧바로 다시 보내면 대개 또 실패합니다. 원인이 아직 그대로이기 때문입니다. 간격을 점점 늘리고 약간의 무작위를 섞습니다.

고정 간격 재시도는 클라이언트가 같은 순간에 몰리고 간격을 늘리고 무작위를 섞으면 흩어진다 고정 간격 클라이언트 수천 대가 같은 순간에 몰린다 간격을 늘리고 무작위를 섞는다 간격이 벌어지고 시점이 흩어진다

무작위가 더 중요합니다. 없으면 같은 시점에 끊긴 클라이언트 수천 대가 같은 간격을 세다가 같은 순간에 동시에 재시도해서, 서버가 회복하려는 순간에 다시 밀려 들어옵니다.

무한 재시도는 장애를 늘린다

서버가 이미 힘든 상태에서 모든 클라이언트가 끝없이 재시도하면 회복을 막습니다. 시도 횟수 상한을 두고, 넘으면 사용자에게 알리고 멈춥니다. 자동 재시도가 항상 친절한 것은 아닙니다.

면접에서 이렇게 나옵니다

Q.모바일 비중이 높은 환경에서 업로드를 어떻게 설계하나요

끊김을 정상 상황으로 전제합니다. 모바일이 60퍼센트 이면 실패 경로가 예외가 아니라 주 경로 중 하나입니다.

세 가지가 필요합니다.

항목없으면
파트 단위 분할끊길 때마다 파일 전체를 다시 보낸다
재개 가능한 상태앱을 다시 켜면 처음부터 시작한다
멱등 키재시도가 파일을 두 개 만든다

재개 상태는 서버의 업로드 세션에 두거나, 스토리지에 이미 올라간 파트 목록을 조회해 빠진 것만 보내는 방식으로 만듭니다. 후자는 클라이언트가 상태를 안 들고 있어도 됩니다.

흔한 실수: 재시도만 붙이고 재개를 안 만드는 것. 재시도는 같은 것을 다시 보내는 것이고 재개는 남은 것만 보내는 것입니다. 50GB 를 재시도하면 처음부터입니다.

Q.업로드 재시도가 파일을 두 개 만드는 것을 어떻게 막나요

멱등 키로 막습니다. 재시도 자체를 없앨 수는 없습니다.

끊김의 절반은 응답을 못 받은 것이고, 그때 요청이 서버에 닿았는지 알 수 없습니다. 그래서 클라이언트는 다시 보내야 하고, 서버는 그것이 재시도인지 알아야 합니다.

업로드를 시작할 때 클라이언트가 키를 하나 만든다
완료 요청에 그 키를 함께 보낸다
서버는 같은 키를 이미 처리했으면 새로 만들지 않고 앞의 결과를 돌려준다

파트 업로드 자체는 같은 번호에 덮어쓰므로 원래 멱등합니다. 위험한 것은 완료 처리입니다. 파일 레코드 생성, 알림 발송, 사용량 차감이 두 번 일어날 수 있습니다.

흔한 실수: 서버가 만든 업로드 식별자를 멱등 키로 쓰는 것. 업로드를 시작하는 요청 자체가 재시도되면 식별자가 두 개 생깁니다. 키는 클라이언트가 만들어야 그 경계도 덮입니다.

Q.재시도 간격은 어떻게 정하나요

간격을 점점 늘리고 무작위를 섞습니다.

곧바로 다시 보내면 대개 또 실패합니다. 원인이 아직 그대로이기 때문입니다. 간격을 늘리면 그 사이에 원인이 사라질 시간이 생깁니다.

무작위가 더 중요합니다. 없으면 같은 시점에 끊긴 클라이언트들이 같은 간격을 세다가 같은 순간에 동시에 재시도합니다. 서버가 회복하려는 순간에 다시 밀려 들어옵니다.

설정결과
고정 간격클라이언트들이 동기화되어 몰린다
늘어나는 간격원인이 사라질 시간을 준다
무작위를 섞음몰림이 흩어진다

흔한 실수: 무한 재시도로 두는 것. 서버가 이미 힘든 상태에서 모든 클라이언트가 끝없이 시도하면 회복을 막습니다. 상한을 두고 넘으면 사용자에게 알리고 멈춥니다. 자동 재시도가 항상 친절한 것은 아닙니다.

Q.재개 상태를 서버에 두면 무엇을 더 관리해야 하나요

세션을 정리하는 정책이 필요합니다. 상태는 쌓이는 성질이 있습니다.

사용자가 업로드를 시작하고 그만두는 것은 흔한 일입니다. 그때마다 업로드 세션 레코드가 남고, 스토리지에는 올라간 파트가 남습니다.

남는 것어디에정리 방법
업로드 세션데이터베이스만료 시각을 두고 배치로 지운다
올라간 파트스토리지미완성 업로드 자동 삭제 규칙

두 정리 주기가 어긋나면 문제가 생깁니다. 세션을 먼저 지우면 파트가 고아로 남고, 파트를 먼저 지우면 세션이 이어갈 수 없는 상태를 가리킵니다. 세션 만료를 파트 삭제보다 짧게 두고, 만료된 세션은 재개 불가로 응답하는 편이 안전합니다.

흔한 실수: 재개를 위해 세션을 오래 살려 두는 것. 며칠 지난 업로드를 이어가는 경우는 드물고, 그동안 파트 저장 요금과 세션 레코드가 계속 쌓입니다.

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

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

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