[Node.js] Redis 데이터베이스를 활용한 Node.js cron-cluster 동시 실행 문제 해결하기
Redis 데이터베이스를 활용한 Node.js cron-cluster 동시 실행 문제 해결하기
1. 문제 상황
최근 개발 중 한 대의 서버에서 두 개의 Node.js 프로젝트를 동시에 실행하면서 흥미로운 문제에 직면했다. 두 프로젝트 모두 cron-cluster
와 Redis를 사용해 예약 작업을 관리하고 있었는데, 두 프로젝트를 동시에 실행하면 두 프로젝트 모두 크론 작업이 동작하지 않았다. 그러나 프로젝트를 각각 따로 실행하면 크론 작업이 정상적으로 동작했다.
2. 원인 분석
이 문제의 원인은 cron-cluster
라이브러리의 작동 방식에 있었다. cron-cluster
는 분산 환경에서 중복 실행을 방지하기 위해 설계되었으며, Redis를 통해 작업 실행을 조율한다. 두 프로젝트가 동일한 Redis 인스턴스와 동일한 크론 작업 식별자를 사용하고 있었기 때문에, 라이브러리는 이를 충돌 상황으로 간주하여 두 프로젝트 모두에서 크론 작업을 실행하지 않았다.
문제가 되었던 두 프로젝트의 코드는 다음과 같았다:
// 프로젝트 1
var redis = require('redis').createClient()
var CronJob = require('cron-cluster')(redis).CronJob
function doCron() {
var job = new CronJob('* * * * *', function() {
// Do some stuff here
})
job.start()
}
// 프로젝트 2 (거의 동일한 코드)
var redis = require('redis').createClient()
var CronJob = require('cron-cluster')(redis).CronJob
function doCron() {
var job = new CronJob('* * * * *', function() {
// Do some stuff here
})
job.start()
}
3. 해결 방법: Redis 데이터베이스 분리하기
여러 해결 방법 중 Redis 데이터베이스를 분리하는 방법을 선택했다. Redis는 기본적으로 0부터 15까지 16개의 데이터베이스를 제공하며, 이를 활용하여 각 프로젝트가 서로 다른 데이터베이스를 사용하도록 했다.
// 프로젝트 1 - 데이터베이스 0 사용
var redis = require('redis').createClient();
redis.select(0); // 기본 데이터베이스 사용
var CronJob = require('cron-cluster')(redis).CronJob;
function doCron() {
var job = new CronJob('* * * * *', function() {
// 프로젝트 1의 작업 내용
console.log('Project 1 cron job running at:', new Date());
});
job.start();
}
// 프로젝트 2 - 데이터베이스 1 사용
var redis = require('redis').createClient();
redis.select(1); // 다른 데이터베이스 인덱스 사용
var CronJob = require('cron-cluster')(redis).CronJob;
function doCron() {
var job = new CronJob('* * * * *', function() {
// 프로젝트 2의 작업 내용
console.log('Project 2 cron job running at:', new Date());
});
job.start();
}
redis.select()
를 사용하여 각 프로젝트가 서로 다른 Redis 데이터베이스를 사용하도록 설정함으로써, 두 프로젝트의 크론 작업이 서로 영향을 주지 않고 독립적으로 실행될 수 있게 되었다.
4. 다른 해결 방법들
이 외에도 다음과 같은 방법으로 문제를 해결할 수 있다:
- 고유한 작업 키 지정:
jobKey
옵션을 사용하여 각 크론 작업에 고유한 식별자를 지정한다.
var job = new CronJob({
cronTime: '* * * * *',
onTick: function() { /* ... */ },
jobKey: 'project1-cron-job' // 또는 'project2-cron-job'
});
- 다른 Redis 인스턴스 사용: 각 프로젝트에서 다른 포트로 연결된 별도의 Redis 인스턴스를 사용한다.
var redis = require('redis').createClient(6379); // 프로젝트 1용 포트
// 또는
var redis = require('redis').createClient(6380); // 프로젝트 2용 포트
5. 결론
분산 환경에서 중복 작업 실행을 관리하는 cron-cluster
의 특성을 이해하고, Redis 데이터베이스를 분리함으로써 같은 서버에서 여러 프로젝트의 크론 작업을 독립적으로 실행할 수 있게 되었다. 이러한 방법은 환경 구성을 변경하지 않고도 기존 코드에 최소한의 수정만으로 문제를 해결할 수 있어 효율적이었다.
분산 시스템에서 예약 작업을 관리할 때는 작업 식별자와 저장소 구성에 특별히 주의해야 한다. 이러한 경험을 통해 애플리케이션의 실행 환경과 사용 중인 라이브러리의 동작 방식을 잘 이해하는 것이 얼마나 중요한지 다시 한번 깨닫게 되었다.