본문 바로가기
프로젝트 답지

React Native에서 대용량 동영상 업로드 최적화

by 띠리에이터 2025. 3. 7.

대용량 동영상을 업로드하는 과정에서 메모리 과부하(OOM)로 인해 앱이 튕기는 문제가 발생했다.
처음에는 단순한 업로드 방식을 사용했지만, 테스트 과정에서 여러 가지 성능 문제가 드러났다.
해결하기 위해 파일 압축, 업로드 방식 변경, 캐시 최적화 등의 방법을 적용,


🚨 문제점: 대용량 동영상 업로드 시 메모리 과부하(OOM) 발생

초기 방식: 파일을 한 번에 업로드

처음에는 expo-file-system을 사용하여 동영상을 업로드하는 간단한 방식을 적용했다.
파일을 선택한 후 그대로 서버에 전송하는 방식이었는데,
이 방식에는 치명적인 문제가 있었다.

📌 초기 방식의 문제점

  1. 파일 크기 제한
    • 파일을 한 번에 업로드하는 방식이라, 2GB 이상의 파일은 업로드 도중 앱이 강제 종료됨
  2. 메모리 과부하(OOM) 발생
    • 파일이 한꺼번에 메모리에 적재되면서, 메모리 부족으로 인해 앱이 튕김
  3. 네트워크 지연
    • 대용량 파일을 그대로 업로드하는 경우, 네트워크 부하가 커져 업로드 속도가 급격히 느려짐

🔍 문제 해결 과정

1.  첫 번째 개선: 동영상 압축 적용

처음 시도한 해결 방법은 동영상을 압축하여 업로드하는 것이었다.
이를 위해 react-native-compressor 라이브러리를 사용했다.

📌 적용 방법

const compressedUrl = await compressedVideo.compress(uri, {
  compressionMethod: "auto", // 파일 크기와 해상도를 기반으로 자동 압축
});
console.log("압축된 URL:", compressedUrl);

압축 적용 후 결과

  • 파일 크기 감소100MB → 7MB로 압축
  • 업로드 속도 향상 → 기존 2분 30초 → 10초로 단축

하지만 새로운 문제 발생

  • 파일 압축 후 tmp 폴더로 이동하여 캐시 삭제 불가능
  • 일부 파일은 압축 후 용량이 더 커지는 현상 발생

압축을 통해 업로드 속도를 개선할 수 있었지만,
파일 관리 문제가 생기면서 다른 접근 방식이 필요했다.


2.  두 번째 개선: 멀티파트 업로드 적용 (Blob 슬라이싱)

파일을 한 번에 업로드하는 방식 대신,
파일을 여러 개의 조각(Chunk)으로 나눠서 업로드하는 멀티파트 업로드 방식을 적용했다.

📌 적용 방법

  • Blob.slice()를 사용하여 5MB 단위로 파일을 분할 업로드
  • for-await-of을 사용하여 파일을 순차적으로 업로드하여 CPU 및 메모리 사용량 최적화
const chunkSize = 5 * 1024 * 1024; // 5MB 단위로 파일을 슬라이스

for (let start = 0; start < file.size; start += chunkSize) {
  const chunk = file.slice(start, start + chunkSize);
  await uploadChunk(chunk);
}

멀티파트 업로드 적용 후 결과

  • 파일을 한 번에 메모리에 올리지 않아도 됨 → OOM(메모리 부족) 방지
  • 업로드 도중 실패한 경우, 실패한 조각만 재전송 가능 → 안정성 증가
  • 대용량 파일(2GB 이상)도 안정적으로 업로드 가능

하지만 새로운 문제 발생

  • 업로드 진행률 표시가 어렵고, 추가적인 서버 구현 필요

3.  최종 개선: 네이티브 스트리밍 업로드 적용 (expo-file-system.uploadAsync)

마지막으로 적용한 방법은 네이티브 스트리밍 업로드였다.
기존 멀티파트 업로드 방식에서는 파일을 조각내서 업로드해야 했지만,
이 방식은 파일을 메모리에 적재하지 않고 스트리밍 방식으로 업로드하는 방법이다.

📌 적용 방법

  • expo-file-system.uploadAsync()를 활용하여 파일을 직접 스트리밍 방식으로 업로드
  • 메모리 과부하 없이 대용량 파일을 업로드 가능
const uploadTask = FileSystem.createUploadTask(
  uploadUrl,
  fileUri,
  {
    httpMethod: "PUT",
    uploadType: FileSystem.FileSystemUploadType.BINARY_CONTENT,
    headers: { "Content-Type": fileType },
  },
  ({ totalBytesSent, totalBytesExpectedToSend }) => {
    const fileProgress = totalBytesSent / (totalBytesExpectedToSend || 1);
    const overallProgress = Math.round(
      ((index + fileProgress) / videoUrl.length) * 100
    );
    setProgress(overallProgress);
  }
);
const uploadResult = await uploadTask.uploadAsync();

네이티브 스트리밍 업로드 적용 후 결과

  • 파일을 메모리에 올리지 않고 직접 업로드 → OOM 완벽 해결
  • 진행률 콜백을 활용하여 업로드 상태 표시 가능
  • 업로드 속도 기존 대비 2배 이상 향상

📉 성과 비교

개선 전개선 후

2GB 이상 파일 업로드 시 앱 튕김 ✅ OOM 발생 없이 대용량 파일 안정적 업로드
파일 업로드 속도 느림 (2분 30초 소요) ✅ 파일 압축 후 10초 이내 업로드 가능
업로드 진행률 표시 불가능 ✅ 진행률 표시 가능 (UI 개선)
네트워크 부하 증가 ✅ 멀티파트 업로드 & 스트리밍 방식 적용으로 최적화