본문 바로가기
개발정리 (nodeJS)

[nodeJS] Node.js에서 대규모 파일 업로드 처리하기

by 할리갈리0 2024. 6. 28.

웹 애플리케이션에서 이미지, 비디오, 문서 등의 파일을 업로드하는 기능은 필수적입니다. 특히 대용량 파일을 업로드할 때는 서버 메모리의 효율적 사용과 사용자 경험을 고려해야 합니다. 스트리밍과 버퍼링을 이용하면 메모리 사용량을 최소화하고, 파일 업로드 속도를 최적화할 수 있습니다.

 

1. 스트리밍과 버퍼링의 기본 개념

스트리밍

  • 데이터를 작은 조각으로 나누어 전송하는 방식
  • 파일을 스트리밍하면 전체 파일을 메모리에 저장하지 않고, 데이터를 순차적으로 처리 가능
  • 메모리 사용을 절약하고, 대용량 파일을 효율적으로 처리하는 데 유리

버퍼링

  • 데이터를 일정량 모아 한꺼번에 처리하는 방식
  • 파일 업로드 시 일정 크기의 버퍼를 사용해 데이터를 저장하고, 일정량이 모이면 처리
  • 데이터 전송의 효율성을 높이고, 네트워크 자원을 효과적으로 활용 가능

 

2. 스트리밍을 이용한 파일 업로드 및 메타데이터 저장

대규모 파일을 업로드하고, 메타데이터를 MongoDB에 저장하기  위해 busboy와 mongoose 모듈 설치

npm install busboy mongoose

 

클라이언트가 업로드한 파일을 스트리밍 방식으로 서버에 저장하고, 파일의 메타데이터를 MongoDB에 저장하는 방식

  1. busboy 모듈을 사용해 파일을 스트림으로 읽어 fs.createWriteStream을 통해 서버에 저장
  2. mongoose를 사용해 파일 메타데이터를 저장
const express = require('express');
const Busboy = require('busboy');
const fs = require('fs');
const path = require('path');
const mongoose = require('mongoose');
const app = express();
const port = 3000;

// MongoDB 연결 설정
mongoose.connect('mongodb://localhost:27017/fileuploads', { useNewUrlParser: true, useUnifiedTopology: true });

// 파일 메타데이터 스키마 정의
const fileSchema = new mongoose.Schema({
    filename: String,
    filepath: String,
    size: Number,
    uploadDate: { type: Date, default: Date.now }
});

const File = mongoose.model('File', fileSchema);

app.post('/upload', (req, res) => {
    const busboy = new Busboy({ headers: req.headers });
    busboy.on('file', (fieldname, file, filename) => {
        const saveTo = path.join(__dirname, 'uploads', filename);
        const fileStream = fs.createWriteStream(saveTo);
        let fileSize = 0;

        file.on('data', (data) => {
            fileSize += data.length;
        });

        file.pipe(fileStream);

        file.on('end', () => {
            const newFile = new File({
                filename,
                filepath: saveTo,
                size: fileSize
            });

            newFile.save((err) => {
                if (err) {
                    return res.status(500).send('파일 메타데이터 저장 중 오류 발생');
                }
                res.send('파일 업로드 및 메타데이터 저장 완료');
            });
        });
    });
    busboy.on('finish', () => {
        console.log('Upload complete');
    });
    return req.pipe(busboy);
});

app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});

 

3. 버퍼링을 이용한 파일 업로드 및 메타데이터 저장

버퍼링 방식을 사용해 파일을 업로드하고, 파일의 메타데이터를 MongoDB에 저장

req.on('data') 이벤트를 통해 데이터를 일정량씩 받아 fs.createWriteStream을 사용해 파일에 기록하며, 업로드가 완료되면 메타데이터를 MongoDB에 저장

const express = require('express');
const fs = require('fs');
const path = require('path');
const mongoose = require('mongoose');
const app = express();
const port = 3000;

// MongoDB 연결 설정
mongoose.connect('mongodb://localhost:27017/fileuploads', { useNewUrlParser: true, useUnifiedTopology: true });

// 파일 메타데이터 스키마 정의
const fileSchema = new mongoose.Schema({
    filename: String,
    filepath: String,
    size: Number,
    uploadDate: { type: Date, default: Date.now }
});

const File = mongoose.model('File', fileSchema);

app.post('/upload', (req, res) => {
    const filePath = path.join(__dirname, 'uploads', 'uploaded_file');
    const writeStream = fs.createWriteStream(filePath);
    let fileSize = 0;

    req.on('data', (chunk) => {
        fileSize += chunk.length;
        writeStream.write(chunk);
    });

    req.on('end', () => {
        writeStream.end();
        const newFile = new File({
            filename: 'uploaded_file',
            filepath: filePath,
            size: fileSize
        });

        newFile.save((err) => {
            if (err) {
                return res.status(500).send('파일 메타데이터 저장 중 오류 발생');
            }
            res.send('파일 업로드 및 메타데이터 저장 완료');
        });
    });
});

app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});

 

4. 파일 업로드 시 주의사항 및 최적화 방법

주의사항

  • 보안: 파일 업로드 시 악성 파일이 서버에 업로드되지 않도록 파일 유형 검사 수행 필요
  • 디스크 용량: 대용량 파일이 서버 디스크 용량을 초과하지 않도록 주의
  • 에러 처리: 파일 업로드 중 발생할 수 있는 에러 처리 필요

 

최적화 방법

  • 압축: 업로드된 파일을 압축해 저장 공간 절약
  • CDN 사용: 파일을 서버 대신 CDN에 저장하여 서버 부하 감소
  • 청크 업로드: 파일을 작은 청크로 나누어 업로드하고, 서버에서 이를 조합하여 저장

 

스트리밍은 메모리 사용을 최소화하고, 버퍼링은 데이터 전송 효율성을 높여줍니다. 이 두 가지 기술을 적절히 활용하면 대용량 파일을 효과적으로 처리할 수 있습니다. 파일 업로드 시 보안, 디스크 용량, 에러 처리 등의 주의사항을 염두에 두고, 최적화 방법을 적용하여 더 나은 성능을 제공할 수 있습니다.

반응형