1. 문제 상황 (Problem)
- 공연을 선택했을 때 좌석 상태가 사람이 눈으로 느낄 수 있을 정도로 늦게 올라오는 현상 발견, 원래는 페이지 진입과 거의 동시에 좌석 상태가 바로 렌더링 되어야 하는데 그보다 눈에 띄게 지연됨
2. 원인 분석 (Cause)
- 좌석 조회 로직 코드 확인 중 Redis에서 좌석 하나하나마다 개별 GET 요청을 보내고 있는 구조임을 발견 (좌석 360개 = 요청 360번)
- 요청마다 네트워크 왕복이 발생하고 누적되어 응답 지연으로 이어진다는 것을 파악
- 단건 조회의 비효율성을 개선하고자 다건을 일괄 처리하여 통신 횟수를 줄일 수 있는 방안 리서치
- 리서치 결과 Redis의 multiGet을 확인, 여러 키를 한 번의 요청으로 조회할 수 있어 반복 조회가 많은 상황에 효과적이라는 것을 파악
3. 해결 방법 (Solution)
- 기존 단건 GET 요청 로직을 Redis multiGet으로 변경
- 360번의 개별 네트워크 통신을 단 1번의 통신으로 병합하여 처리

4. 결과 (Result)
- 동일 로직을 재현한 환경에서 측정한 결과, 응답 시간이 64.19ms → 2.06ms로 단축
- 단순 조회 속도뿐만 아니라 인프라 간 네트워크 통신 최소화가 성능 최적화의 핵심임을 체감
# 재현 코드 (테스트)
package com.example.ticketing;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.*;
public class RedisBenchmark {
public static void main(String[] args) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(
new RedisStandaloneConfiguration("localhost", 6379));
factory.afterPropertiesSet();
StringRedisTemplate redisTemplate = new StringRedisTemplate();
redisTemplate.setConnectionFactory(factory);
redisTemplate.afterPropertiesSet();
List<String> keys = new ArrayList<>();
for (long i = 1; i <= 360; i++) {
String key = "seat:" + i;
redisTemplate.opsForValue().set(key, "userA");
keys.add(key);
}
int rounds = 10;
long totalIndividual = 0;
long totalMulti = 0;
for (int r = 0; r < rounds; r++) {
long start = System.nanoTime();
for (String key : keys) {
redisTemplate.opsForValue().get(key);
}
totalIndividual += (System.nanoTime() - start);
start = System.nanoTime();
redisTemplate.opsForValue().multiGet(keys);
totalMulti += (System.nanoTime() - start);
}
double avgIndividualMs = (totalIndividual / rounds) / 1_000_000.0;
double avgMultiMs = (totalMulti / rounds) / 1_000_000.0;
System.out.printf("360회 개별 조회 평균: %.2f ms%n", avgIndividualMs);
System.out.printf("multiGet 1회 평균: %.2f ms%n", avgMultiMs);
System.out.printf("개선율: %.1f%% 단축%n", (1 - avgMultiMs / avgIndividualMs) * 100);
factory.destroy();
}
}