수강신청 시스템에서 가장 까다로운 부분은 단순히 대기열을 유지하는 것이 아니라
"입장이 허용된 사용자가 실제로 로그인까지 완료했는지"를 추적하고 "빈자리가 생겼을 때 누굴 입장시킬지" 정확히 판단하는 것이다.
초기에는 서버 내부에서 아래와 같이 관리했다.
List<QueueUser> 형태로 메모리에 저장Map<Long studentId, Long timestamp> 으로 추적/notify)을 보내 ALLOWED 처리를 요청이 구조는 간단하지만 다음과 같은 명확한 한계가 있었다:
| 문제점 | 설명 |
|---|---|
| ❌ 정합성 | 사용자가 ALLOWED 메시지를 받은 후 실제 로그인하지 않는 경우, 해당 자리는 낭비되며 시스템은 이를 인지할 수 없었다. |
| ❌ 수동 관리 | 미입장 사용자에 대한 회수를 위해 BatchManager나 스케줄러가 필요했고 관리가 번거로웠다. |
| ❌ 강한 결합 | 수강신청 서버가 대기열 서버의 주소와 API 경로(/notify)를 알아야 했고 HTTP 연결 실패 시 장애가 전파될 위험이 있었다. |
이러한 문제를 해결하기 위해 시스템은 전체 구조를 Redis 중심으로 재설계했다.
단순한 캐시 용도가 아닌, 실시간 데이터 처리, 자동 만료, 비동기 메시지 전송까지 담당하는 핵심 인프라로 동작하게 되었다.
| 목적 | Redis 구조 | 설명 |
|---|---|---|
| 대기열 순서 관리 | List | Redis의 List에 사용자 토큰을 RPUSH 하고, 입장 시에는 LPOP으로 제거 |
| 빈자리 알림 | Pub/Sub 채널 | 수강신청 서버에서 PUBLISH로 알림을 보내고, 대기열 서버는 해당 채널을 SUBSCRIBE하여 실시간 메시지를 수신| |
| 인증 사용자 세션 | Key-Value + TTL | 사용자가 로그인하면 session:{studentId} 키를 TTL과 함께 Redis에 저장하고, 일정 시간이 지나면 자동으로 삭제되도록 구성 |
| 인증 사용자 수 집계 | Set | 인증된 사용자 키의 개수를 기반으로 Redis에서 빠르게 입장 인원을 파악 |
입장 후 로그인 여부를 시스템이 자동으로 판단할 수 있다.
TTL이 설정된 키를 통해 사용자가 로그인하지 않으면 자동으로 자리가 회수되고 별도의 관리 로직이 필요 없다.
빈자리 발생 시 대기열 서버로 정확하게 알릴 수 있게 되었다.
기존에는 HTTP 요청으로 수동 알림을 보냈지만, 이제는 Redis Pub/Sub을 사용하여 수강신청 서버가 메시지를 발행하면
대기열 서버는 이를 구독 중인 상태에서 자동으로 수신하여 실시간으로 반응할 수 있게 되었다.

👉 서버 간 강한 의존 없이 느슨하게 연결되는 구조(Low Coupling)로 바뀌었다.
순번 계산이 간단하다.
LPOS, LRANGE 등을 통해 Redis 내부에서 순번을 계산할 수 있어서 별도의 인덱스 관리가 필요 없기에 대기 순번도 자동으로 이동된다.
BatchManager가 필요 없게 되었다.
기존에는 미입장 사용자를 수동으로 관리하기 위해 별도의 로직이 존재하였지만, Redis TTL 구조로 자동 만료가 가능해지면서 이 기능을 제거할 수 있게 되었다.
➡️ 대기열 접속 시 해당 사용자의 토큰을 Redis List에 저장
redisTemplate.opsForList().rightPush("queue:waiting", token);
➡️ 사용자에게 SSE를 통해 아래와 같은 메시지를 전송
{
"queueNumber": 125, //대기순번
"status": "WAITING"
}
➡️ 빈자리 발생 → 입장 로직
수강신청 서버에서 로그아웃, TTL 만료 등 변화 발생 시
stringRedisTemplate.convertAndSend("entrance-channel", String.valueOf(currentSessionCount));
대기열 서버는 entrance-channel을 구독 중이며 메시지를 수신하면 다음 순서로 로직을 수행한다:
stringRedisTemplate.opsForValue().set(
"session:" + studentId,
"active",
SESSION_TTL,
TimeUnit.MILLISECONDS
);
TTL이 지나면 자동 삭제되어 별도 정리 필요 없음 → 빈자리 발생으로 간주 가능
또한 수강신청 서버는 현재 인증된 사용자 수를 Redis에서 즉시 조회 가능
Redis 도입은 단순한 성능 향상이 아닌
정확하게 입장시킬 사람을 판단하고, 로그인하지 않은 사용자의 자리를 시스템이 자동으로 회수할 수 있도록 만든 구조 개편이었다.
또한 Pub/Sub 구조 도입을 통해
수강신청 서버와 대기열 서버 간의 의존성을 줄이고 실시간 메시지 전송을 안정적으로 처리할 수 있게 되었다.
✅ “입장”을 판단하고
✅ “알리는 방식”까지 모두 개선함으로써
수강신청 시스템의 실시간성, 정합성, 확장성이 모두 확보되었다.