IT/NodeJS

Node.js로 대량의 API 요청 처리하기

KeepGooing 2024. 12. 2. 11:54
반응형

Node.js로 대량의 API 요청 처리하기

 

대량의 API 요청을 효율적으로 처리하는 것은 Node.js 애플리케이션의 성능과 확장성을 위해 중요합니다. 이 글에서는 Node.js에서 대량의 API 요청을 처리하기 위한 다양한 전략과 기법을 살펴보겠습니다.

1. 요청 배치 처리

여러 개의 API 요청을 하나의 배치로 묶어 처리하는 방법입니다.

const axios = require('axios');

async function batchRequests(urls) {
    const batchSize = 10; // 한 번에 처리할 요청 수
    const results = [];

    for (let i = 0; i < urls.length; i += batchSize) {
        const batch = urls.slice(i, i + batchSize);
        const batchPromises = batch.map(url => axios.get(url));
        const batchResults = await Promise.all(batchPromises);
        results.push(...batchResults);
    }

    return results;
}

// 사용 예
const urls = ['url1', 'url2', 'url3', /* ... */];
batchRequests(urls).then(results => console.log(results));
        

설명: 이 방법은 전체 요청을 작은 배치로 나누어 처리합니다. 각 배치는 동시에 처리되며, 한 배치가 완료된 후 다음 배치로 넘어갑니다. 이를 통해 동시 요청 수를 제어하고 서버 부하를 관리할 수 있습니다.

2. 속도 제한 구현

API 요청의 속도를 제한하여 서버 과부하를 방지합니다.

const axios = require('axios');
const RateLimiter = require('limiter').RateLimiter;

const limiter = new RateLimiter(5, 'second'); // 초당 5개 요청으로 제한

async function rateLimitedRequest(url) {
    return new Promise((resolve, reject) => {
        limiter.removeTokens(1, async () => {
            try {
                const response = await axios.get(url);
                resolve(response.data);
            } catch (error) {
                reject(error);
            }
        });
    });
}

// 사용 예
const urls = ['url1', 'url2', 'url3', /* ... */];
Promise.all(urls.map(rateLimitedRequest))
    .then(results => console.log(results));
        

설명: 이 방법은 요청 속도를 제어하여 API 서버의 제한을 준수하고 안정적인 처리를 보장합니다. limiter 라이브러리를 사용하여 초당 요청 수를 제한합니다.

3. 스트리밍 활용

대용량 데이터를 처리할 때 스트리밍을 사용하여 메모리 사용을 최적화합니다.

const fs = require('fs');
const axios = require('axios');
const { Transform } = require('stream');

async function streamRequests(urls, outputFile) {
    const writeStream = fs.createWriteStream(outputFile);

    const requestStream = new Transform({
        objectMode: true,
        transform(url, encoding, callback) {
            axios.get(url)
                .then(response => {
                    this.push(JSON.stringify(response.data) + '\n');
                    callback();
                })
                .catch(error => callback(error));
        }
    });

    return new Promise((resolve, reject) => {
        requestStream
            .pipe(writeStream)
            .on('finish', resolve)
            .on('error', reject);

        urls.forEach(url => requestStream.write(url));
        requestStream.end();
    });
}

// 사용 예
const urls = ['url1', 'url2', 'url3', /* ... */];
streamRequests(urls, 'output.json')
    .then(() => console.log('처리 완료'));
        

설명: 스트리밍 방식을 사용하면 대량의 데이터를 처리할 때 메모리 사용을 최소화할 수 있습니다. 각 요청의 결과를 바로 파일에 쓰기 때문에 모든 결과를 메모리에 보관할 필요가 없습니다.

4. 병렬 처리

Node.js의 클러스터 모듈을 사용하여 여러 프로세스에서 요청을 병렬로 처리합니다.

const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
const axios = require('axios');

if (cluster.isMaster) {
    console.log(`마스터 ${process.pid} 실행 중`);

    const urls = ['url1', 'url2', 'url3', /* ... */];
    let urlIndex = 0;

    // CPU 코어 수만큼 워커 생성
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('message', (worker, message) => {
        if (message.type === 'ready') {
            if (urlIndex < urls.length) {
                worker.send({ type: 'url', url: urls[urlIndex++] });
            } else {
                worker.send({ type: 'exit' });
            }
        }
    });

    cluster.on('exit', (worker, code, signal) => {
        console.log(`워커 ${worker.process.pid} 종료`);
    });
} else {
    console.log(`워커 ${process.pid} 시작`);

    process.on('message', async (message) => {
        if (message.type === 'url') {
            try {
                const response = await axios.get(message.url);
                console.log(`워커 ${process.pid}: ${message.url} 처리 완료`);
            } catch (error) {
                console.error(`워커 ${process.pid}: ${message.url} 처리 실패`, error);
            }
            process.send({ type: 'ready' });
        } else if (message.type === 'exit') {
            process.exit(0);
        }
    });

    process.send({ type: 'ready' });
}
        

설명: 클러스터 모듈을 사용하면 Node.js 애플리케이션을 여러 프로세스로 분산하여 실행할 수 있습니다. 이를 통해 CPU 코어를 최대한 활용하여 대량의 API 요청을 병렬로 처리할 수 있습니다.

결론

Node.js에서 대량의 API 요청을 효율적으로 처리하기 위해서는 요청 배치 처리, 속도 제한, 스트리밍, 병렬 처리 등 다양한 기법을 활용할 수 있습니다. 각 방법은 상황에 따라 장단점이 있으므로, 애플리케이션의 요구사항과 처리해야 할 데이터의 특성을 고려하여 적절한 방법을 선택해야 합니다. 또한, 이러한 기법들을 조합하여 사용하면 더욱 효과적인 처리가 가능합니다. 대량의 API 요청을 처리할 때는 항상 서버의 부하와 네트워크 상태를 모니터링하고, 필요에 따라 전략을 조정하는 것이 중요합니다.

반응형