문제
NestJS에서 Redis Pub/Sub을 사용해 실시간 알림을 구현하던 중, 동일한 메시지가 클라이언트에 중복 전달되는 문제가 발생했습니다.
원인 분석
기존 구현에서는 클라이언트가 WebSocket을 통해 서버에 연결될 때마다 handleConnection 메서드에서 Redis 채널에 대한 구독이 이루어졌습니다. 각 클라이언트가 연결될 때마다 구독이 중복으로 발생해, 동일한 메시지가 여러 번 수신되며 중복된 이벤트로 처리되었습니다. 이로 인해 서버와 클라이언트 간의 성능 저하 및 불필요한 네트워크 트래픽이 발생했습니다.
해결 방법
중복 구독 문제를 해결하기 위해, 구독 로직을 클라이언트의 연결 시점이 아닌, NotificationGateway 클래스가 초기화될 때 한 번만 실행되도록 변경했습니다. 이렇게 함으로써, 여러 클라이언트가 연결되더라도 구독이 중복으로 발생하지 않도록 하였습니다.
@WebSocketGateway({
cors: {
origin: '*',
}
})
export class NotificationGateway {
@WebSocketServer()
server: Server;
private static isSubscribed = false;
constructor(private readonly redisService: RedisService) {
if (!NotificationGateway.isSubscribed) {
this.subscribeToRedis(); // 클래스 초기화 시 구독 수행
NotificationGateway.isSubscribed = true;
}
}
private async subscribeToRedis() {
await this.redisService.subscribe('notifications', (message: string) => {
const parsedMessage = JSON.parse(message);
this.server.emit('notifications', parsedMessage);
});
}
.
.
.
JavaScript
복사
해결된 방법 및 효과
1.
구독 시점 변경: NotificationGateway 클래스가 초기화될 때, 즉 서버가 시작될 때 구독이 한 번만 설정되도록 변경했습니다. 이로 인해 모든 클라이언트에 대해 동일한 Redis 구독을 공유하고, 중복 구독을 방지했습니다.
2.
중복 수신 문제 해결: 구독이 한 번만 설정되었기 때문에, 여러 클라이언트가 연결되더라도 중복된 메시지 수신 없이, Redis에서 수신된 알림을 적절히 받을 수 있게 되었습니다.
결론
Redis Pub/Sub의 구독 로직을 서버 초기화 시점으로 이동시켜 중복 구독 문제를 해결함으로써, 실시간 알림 및 채팅 기능에서의 성능과 안정성을 크게 개선할 수 있었습니다. 이를 통해 효율적이고 확장 가능한 시스템을 구축할 수 있었습니다.