Node.js 멀티파트 파일 업로드 처리 시 메모리 이슈 해결
문제 상황
이미지 업로드 기능에서 10MB 이상의 파일이 여러 개 동시에 업로드되면 서버 메모리 사용량이 급증하며 502 에러가 발생했다. 기존에는 busboy를 직접 사용해서 파일을 메모리에 버퍼로 저장한 후 S3에 업로드하는 방식이었다.
원인 분석
모든 파일 데이터를 메모리에 적재한 후 처리하는 구조였다. 동시 요청이 5개만 들어와도 50MB 이상의 메모리를 순간적으로 사용하게 되어 t2.small 인스턴스에서는 감당이 안 됐다.
// 문제가 있던 코드
app.post('/upload', (req, res) => {
const chunks = [];
req.on('data', chunk => chunks.push(chunk));
req.on('end', () => {
const buffer = Buffer.concat(chunks); // 전체 메모리 적재
uploadToS3(buffer);
});
});
해결 방법
multer를 도입하고 스트리밍 방식으로 변경했다. multer-s3를 사용하여 파일을 메모리에 버퍼링하지 않고 바로 S3로 스트리밍하도록 수정했다.
const multer = require('multer');
const multerS3 = require('multer-s3');
const aws = require('aws-sdk');
const s3 = new aws.S3();
const upload = multer({
storage: multerS3({
s3: s3,
bucket: 'my-bucket',
key: (req, file, cb) => {
cb(null, `${Date.now()}_${file.originalname}`);
}
}),
limits: { fileSize: 20 * 1024 * 1024 }
});
app.post('/upload', upload.array('files', 10), (req, res) => {
res.json({ files: req.files.map(f => f.location) });
});
결과
메모리 사용량이 평균 80MB에서 10MB 이하로 감소했다. 동시 업로드 처리 시에도 안정적으로 동작하며, 인스턴스 스펙을 올리지 않고도 문제를 해결할 수 있었다.
파일 업로드 같은 I/O 작업은 스트리밍 방식이 필수라는 점을 다시 확인했다.