Node.js 22 Worker Threads로 이미지 일괄 처리 성능 개선
문제 상황
사용자가 업로드한 이미지를 여러 크기로 리사이징하는 배치 작업이 있었다. 한 번에 수백 장의 이미지를 처리하다 보니 메인 스레드가 블로킹되어 API 응답 시간이 급격히 증가했다.
기존 코드는 sharp 라이브러리를 순차적으로 호출하는 구조였다.
for (const image of images) {
await sharp(image.path)
.resize(800, 600)
.toFile(outputPath);
}
Worker Threads 도입
Node.js의 Worker Threads를 사용해 이미지 처리를 병렬화했다. CPU 코어 수만큼 워커를 생성하고 작업을 분산시켰다.
import { Worker } from 'worker_threads';
import os from 'os';
const numWorkers = os.cpus().length;
const workers = [];
for (let i = 0; i < numWorkers; i++) {
workers.push(new Worker('./image-worker.js'));
}
let currentWorker = 0;
for (const image of images) {
const worker = workers[currentWorker];
worker.postMessage({ path: image.path, output: outputPath });
currentWorker = (currentWorker + 1) % numWorkers;
}
워커 파일은 다음과 같이 작성했다.
// image-worker.js
import { parentPort } from 'worker_threads';
import sharp from 'sharp';
parentPort.on('message', async ({ path, output }) => {
try {
await sharp(path)
.resize(800, 600)
.toFile(output);
parentPort.postMessage({ success: true, output });
} catch (error) {
parentPort.postMessage({ success: false, error: error.message });
}
});
결과
500장의 이미지 처리 시간이 8분에서 2.5분으로 단축되었다. 메인 스레드 블로킹도 해결되어 API 응답 시간이 정상화되었다.
주의할 점은 워커 간 메모리를 공유하지 않는다는 것이다. 큰 데이터를 전달할 때는 SharedArrayBuffer나 파일 경로를 활용하는 것이 효율적이다.