파일 업로드 중단 재개와 청크 업로드 전략
대용량 파일 업로드에서 네트워크 중단 시 전송을 안전하게 재개하는 방법과 청크 기반 업로드 전략을 Node.js 중심으로 정리한 기술자료
목차
개요
대용량 파일을 전송할 때 네트워크 문제나 클라이언트 오류로 전송이 중단되는 경우가 빈번하다. 이를 해결하려면 업로드를 중단 지점부터 재개(resume)할 수 있어야 한다. 이 글은 Node.js 환경에서 청크 업로드와 재개 전략을 이해하기 쉽게 설명한다. 기본 개념부터 클라이언트·서버 설계, 구현 예제, 검증 방법까지 다룬다.
왜 재개 가능한 업로드가 필요한가
대용량 파일은 전송 시간이 길다. 작은 네트워크 장애만으로도 전체 업로드가 무효화되면 사용자 경험이 크게 저하된다. 재개 기능은 다음 이점을 제공한다.
- 중단된 지점부터 이어서 전송 가능
- 실패 시 재전송 비용 절감
- 동시 업로드 처리와 안정성 향상
핵심 개념
청크(chunk)
파일을 일정 크기 단위(예: 1MB)로 나눈 조각을 청크라고 한다. 청크 단위 전송은 실패 시 재전송 범위를 줄여준다.
업로드 식별자(uploadId)
클라이언트가 업로드를 시작할 때 서버에서 발급하는 고유 ID다. 이 ID로 청크 상태를 추적하고 조립을 관리한다.
무결성 검증
청크별 체크섬(예: SHA-256)이나 전체 파일 해시를 사용해 데이터 일관성을 확인한다. 중복 업로드 방지에도 유용하다.
설계 전략 요약
- 청크 크기 결정: 네트워크 특성, 메모리 한계, 병렬 전송 가능성 고려
- 상태 추적: DB나 인메모리 캐시에 업로드 진행 상태 저장
- idempotency: 동일 청크 재전송 시 중복 저장 방지
- 검증 단계: 체크섬으로 청크 무결성 확인 후 조립
클라이언트 흐름
클라이언트는 파일을 청크로 분할해 순차 또는 병렬로 전송한다. 각 청크 전송 시 업로드 ID와 청크 인덱스, 체크섬을 함께 보낸다. 업로드 중단 시 마지막으로 확인된 청크 인덱스를 서버에 요청하여 재개 지점을 얻는다.
간단한 클라이언트 예
const file = /* File 객체 */
const CHUNK_SIZE = 1024 * 1024; // 1MB
async function uploadFile(file) {
const uploadId = await initUploadOnServer(file.name, file.size);
let offset = 0;
let index = 0;
while (offset < file.size) {
const chunk = file.slice(offset, offset + CHUNK_SIZE);
const checksum = await hashChunk(chunk);
await sendChunk(uploadId, index, chunk, checksum);
offset += CHUNK_SIZE;
index += 1;
}
await finalizeUpload(uploadId);
}
서버 흐름 (Node.js)
서버는 업로드 초기화, 청크 수신, 상태 저장, 청크 검증, 최종 조립 단계를 처리한다. 상태는 Redis나 데이터베이스에 저장하면 재시작 후에도 복구 가능하다.
간단한 Express 예제
const express = require('express');
const fs = require('fs');
const app = express();
app.post('/init', (req, res) => {
const uploadId = generateId();
// DB에 업로드 메타 저장
res.json({ uploadId });
});
app.post('/chunk', (req, res) => {
const { uploadId, index, checksum } = req.headers;
const chunkBuffer = req.body; // body-parser를 이진으로 설정
if (!verifyChecksum(chunkBuffer, checksum)) return res.status(400).end();
const filePath = getTempPath(uploadId, index);
fs.writeFileSync(filePath, chunkBuffer);
markChunkReceived(uploadId, index);
res.status(200).end();
});
app.post('/complete', (req, res) => {
const { uploadId } = req.body;
assembleChunks(uploadId);
res.json({ ok: true });
});
재개 로직 구현 포인트
- 클라이언트 요청으로 서버에 수신된 청크 목록을 조회하는 API 제공
- 클라이언트는 수신된 인덱스 이후부터만 재전송
- 병렬 전송 시 동시성 제어로 과부하 방지
- 완료 후 임시 청크 파일 삭제 및 메타 정리
검증과 보안
체크섬과 파일 크기 검증으로 무결성을 확보한다. 인증 토큰으로 업로드 권한을 통제하고, 업로드 시간 제한과 용량 제한을 둬 남용을 방지한다. HTTPS 사용은 필수다.
테스트 및 모니터링
장애 시나리오를 만들어 네트워크 단절, 중복 청크, 체크섬 불일치 등을 검증한다. 모니터링 도구로 업로드 실패율과 평균 처리 시간을 측정해 병목을 개선한다.
결론
청크 업로드와 재개 기능은 대용량 파일 전송에서 필수적이다. 설계는 단순하지만 구현 시 상태 관리, 무결성 검증, 보안, 성능을 고려해야 안정적인 시스템을 만들 수 있다. Node.js 환경에서는 Express와 스트리밍, Redis 같은 상태 저장소를 조합하면 실무에 적용 가능한 구조를 빠르게 만들 수 있다.
참고 키워드: Node.js 청크 업로드 구현, resumable file upload Node.js, 대용량 업로드 재개 방법