Node.js 멀티 프로세스 환경에서 메모리 캐시 동기화 문제
문제 상황
트래픽 증가로 단일 프로세스 Node.js 앱을 PM2 클러스터 모드로 전환했다. 기존에 사용하던 인메모리 캐시가 프로세스별로 독립적으로 동작하면서 데이터 불일치 문제가 발생했다.
// 기존 코드
const cache = new Map();
function getUserData(userId) {
if (cache.has(userId)) {
return cache.get(userId);
}
const data = db.query(userId);
cache.set(userId, data);
return data;
}
프로세스 A에서 캐시를 업데이트해도 프로세스 B는 구 데이터를 반환하는 상황이 반복됐다.
해결 방법
Redis를 캐시 레이어로 도입했다. ioredis 라이브러리를 사용했고, 기존 Map 인터페이스와 유사하게 래퍼를 만들어 마이그레이션 비용을 줄였다.
const Redis = require('ioredis');
const redis = new Redis();
async function getUserData(userId) {
const cached = await redis.get(`user:${userId}`);
if (cached) {
return JSON.parse(cached);
}
const data = await db.query(userId);
await redis.setex(`user:${userId}`, 3600, JSON.stringify(data));
return data;
}
고려사항
- 직렬화 비용: JSON.stringify/parse 오버헤드가 있지만, 네트워크 I/O에 비하면 무시할 수준이었다.
- TTL 설정: 기존 인메모리 캐시는 TTL이 없었는데, Redis에서는 명시적으로 설정해야 했다. 데이터 특성에 따라 1시간~24시간으로 차등 적용했다.
- 에러 핸들링: Redis 장애 시 fallback 로직을 추가했다. Redis 연결 실패 시 DB로 직접 쿼리하도록 처리했다.
성능 테스트 결과 응답 시간이 평균 5ms 증가했지만, 데이터 일관성 확보가 더 중요했다. 프로덕션 배포 후 캐시 관련 버그 리포트가 사라졌다.