findRemaining)findAll)findMyOccupy)위 3가지 조회 API는 모두 DB에서 좌석 정보를 조회한 뒤, 각 좌석이 Redis에서 점유(occupy) 중인지를 다시 확인하는 방식이었다.

DB: 특정 회차의 좌석 N건 조회
↓
Redis: 좌석 N건 각각의 occupy Key를 MGET으로 한 번에 조회
↓
두 결과를 합쳐 AVAILABLE / OCCUPIED 판별
콘서트 하나의 좌석 수는 3000석으로 설정하였다. 이 3000건을 매 요청마다 Redis에서 점유 여부로 대조해야
처음에는 redisTemplate.opsForValue().multiGet(occupyKeys) 을 적용하여 좌석마다 흩어진 요청을 왕복 1번으로 묶는 MGET을 사용했다.
그러나, 이것은 RTT만 줄인 것이지 O(N)의 연산으로, 조회량 자체를 줄인 게 아니었다.
// occupy Key 목록 획득
List<String> occupyKeys = scheduleSeatEntities.stream()
.map(scheduleSeat -> ScheduleSeatRedisKeys.occupyKey(scheduleSeat.getId()))
.toList();
// 한 번의 MGET으로 일괄 조회
List<Object> occupyValues = redisUtil.multiGet(occupyKeys);
| avg | p90 | p95 | p99 | ||||
|---|---|---|---|---|---|---|---|
| remaining_seats_duration | 144ms | 1s | 101ms | 11ms | 307ms | 417ms | 673ms |
| seats_duration | 209ms | 1s | 159ms | 27ms | 420ms | 537ms | 812ms |
| my_occupy_duration | 196ms | 1s | 150ms | 22ms | 397ms | 496ms | 772ms |
즉, RTT가 병목이 아니라, 매번 3천건을 훑는 조회 자체가 병목이라고 판단하였다.