Elasticsearch 집계 쿼리 성능 개선 - 캐싱 전략
문제 상황
재택근무가 시작되면서 대시보드 사용량이 급증했다. 특히 일별/주별 통계를 보여주는 페이지에서 응답이 5초 이상 걸리는 경우가 빈번했다. Kibana로 확인해보니 집계 쿼리가 대부분의 시간을 소모하고 있었다.
원인 분석
문제가 된 쿼리는 다음과 같았다.
{
"aggs": {
"daily_stats": {
"date_histogram": {
"field": "timestamp",
"interval": "day"
},
"aggs": {
"unique_users": { "cardinality": { "field": "user_id" } },
"total_amount": { "sum": { "field": "amount" } }
}
}
}
}
3개월치 데이터(약 500만 건)를 매번 집계하고 있었다. 더 큰 문제는 여러 사용자가 동시에 같은 쿼리를 날리고 있다는 점이었다.
해결 방법
1. 쿼리 최적화
먼저 불필요한 필드를 제거하고 _source를 false로 설정했다. 집계에만 필요한 필드만 로드하도록 수정했다.
2. Redis 캐싱
Node.js 서버에서 캐싱 레이어를 추가했다.
const redis = require('redis');
const client = redis.createClient();
async function getDailyStats(startDate, endDate) {
const cacheKey = `stats:${startDate}:${endDate}`;
const cached = await client.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
const result = await esClient.search({
index: 'transactions',
body: buildAggregationQuery(startDate, endDate)
});
await client.setex(cacheKey, 300, JSON.stringify(result));
return result;
}
TTL은 5분으로 설정했다. 실시간성이 중요하지 않은 통계 데이터였기 때문에 충분했다.
3. 날짜 범위 제한
프론트에서 기본적으로 최근 30일만 조회하도록 변경했다. 더 긴 기간이 필요한 경우에만 명시적으로 선택하도록 했다.
결과
- 평균 응답 시간: 5.2초 → 480ms
- 캐시 히트율: 약 78%
- ES 클러스터 부하 50% 감소
재택근무로 트래픽이 늘어나면서 기존에 묻혀있던 성능 이슈가 드러났다. 캐싱은 가장 기본적인 해결책이지만, 확실히 효과가 있었다.