...
Redis Publish / Subscribe
Publish / Subscribe 란 특정한 주제(topic)에 대하여 해당 topic을 구독한 모두에게 메시지를 발행하는 통신 방법으로 채널을 구독한 수신자(클라이언트) 모두에게 메세지를 전송 하는것을 의미한다. 하나의 Client가 메세지를 Publish하면, 이 Topic에 연결되어 있는 다수의 클라이언트가 메세지를 받을 수 있는 구조이다.
쉽게 생각하면, Youtube 채널 구독과 비슷하다. 구독과 좋아요(Subscribe )를 누르면, 나중에 크리에이터가 새로운 글을 발행(Publish)하면 구독자 한테만 알림(notification)이 오게 되는 원리라고 보면 된다.
Publish / Subscribe 구조에서 사용되는 Queue를 일반적으로 Topic이라고 한다.
그래서 레디스의 pub/sub 기능은 은 주로 채팅 기능이나, 푸시 알림등에 사용된다. 이를테면 날씨정보를 구독한 사람에게 주기적으로 날씨정보를 보내거나, 특정한 작업을 반복 수행하는 작업자에게 비동기적으로 작업을 보내 처리하도록 하거나, 또는 현재 앱에 로그인한 유저에게 푸시를 발송하는 활동들이 모두 pub/sub의 원리로 만들어 진다고 보면 된다.
다만 유의할점이 있는데, 이러한 redis의 pub/sub 시스템은 매우 단순한 구조로 되어있다는 것이다. Pub/Sub 시스템에서는 채널에 구독 신청을 한 모든 subscriber에게 메시지를 전달한다. 그런데 메시지를 "던지는" 시스템이기 때문에, 메시지를 따로 보관하지도 않는다. 즉, 수신자(클라이언트)가 메세지를 받는 것을 보장하지 않아, subscribe 대상이 하나도 없는 상황에서 메시지를 publish해도 역시 사라진다. 그래서 일반 메시지큐처럼 수신 확인을 하지 않는다.(전송 보장을 하지 않음)
간단하게 정리하면 메시지를 보내는 쪽도 보내고 끝, 받는 쪽도 받고 끝이 되게 심플하게 되어 있다.
근데 이렇게 단순한 기능만 제공하니 쓸모가 없지 않느냐고 생각할 수 있다. 그러나 웹소켓을 이용할경우 추가적인 네트워크 통신이 필요하기에 레이턴시(딜레이)가 약간 생길수 있다. 반면 레디스는 In-Memory 기반이라 매우 바르게 메세지를 받을 수 있다. 따라서 현재 접속 중인 클라이언트에게 짧고 간단한 메시지를 빠르게 보내고 싶을 때, 그리고 전송된 메시지를 따로 저장하거나 수신확인이 필요 없을 때, 마지막으로 100% 전송 보장은 하지 않아도 되는 데이터를 보낼때 이용하면 괜찮다.
Pub / Sub 명령어
- Redis 서버를 매개로, Redis 클라이언트간 통신을 도와줌
- Redis 클라이언트는 Redis 서버내 "채널"을 생성함
- 메시지를 수신하고 싶은 클라이언트는 사전에 해당 채널을 subscribe 함
- 메시지를 보내는 클라이언트는 해당 채널에 메시지를 publish할 수 있음
- 메시지를 보내는 클라이언트가 메시지를 publish하면, subscribe 중인 클라이언트만 메시지를 수신
Commands | Syntax | Description |
subscribe | channel [channel ...] | 채널을 구독하여, 메세지를 수신 받는다. (동시에 여러개 구독 가능) |
publish | channel message | 메시지를 지정한 채널로 송신 |
pubsub | subcommand [argument [argument ...]] | 서버에 등록된 채널이나 패턴을 조회 |
psubscribe | pattern [pattern ...] | 채널 이름을 패턴으로 등록 |
unsubscribe | [channel [channel ...]] | subscribe로 등록한 채널 구독 해제 |
punsubscribe | [pattern [pattern ...]] | psubscribe로 등록한 패턴 채널 구독 해제 |
redis-cli를 사용해 message를 publish하고 subscribe 실습을 진행해보자. 실습을 위해 2개의 redis client가 필요하다. (그냥 redis-cli.exe 2개 실행하면 된다)
subscribe 명령어
파라미터로 명시한 채널을 구독한다. 여러 개의 채널을 동시에 구독할 수도 있다. 결과값으로 구독한 채널명과 integer를 반환한다.
redis에서는 channel을 생성하는 명령어는 존재하지 않고 subscribe로 채널을 생성하고 구독하는 것으로 보면 된다.
> subscribe <채널명>
> subscribe <채널명1> <채널명2> ... # 여러 개의 채널을 등록하면, 각각의 채널로 메시지가 발행되면 모두 수신한다.
publish 명령어
이제 ch1을 구독하고 있는 subscriber가 생겼으므로, publisher client에서 publish 명령어를 사용해 메시지를 발행하면 subscriber client에서는 해당 메세지를 전달받게 된다.
> publish <채널> <내용>
(integer) 2 # 채널에 메시지를 발행했고, 2개의 클라이언트에게 전달되었음
pubsub 명령어
adminstrator가 효율적으로 subscriber를 관리할 수 있도록 하는 명령어 이다. 다음과 같이 세 가지 subcommand가 있다.
- channels : 활성화 된 채널
- numsub : 특정 채널을 구독하고 있는 subscriber의 갯수를 확인 ( pattern subscription으로 구독하고 있는 subscriber는 count에 포함되지 않음)
- numpat : pattern subscription의 subscriber 갯수 확인 (특정 채널의 subscriber가 아닌, 전체 subscriber의 갯수를 return)
# 활성화된 채널이 없을 때
> pubsub channels
(empty array)
# 아래의 SUBSCRIBE 명령어로 채널을 한 개 활성화 시켰을 때
> pubsub channels
1) "c1"
# 채널을 구독중인 클라이언트 수 확인
> pubsub numsub ch1
1) "ch1"
2) (integer) 1
# 패턴형으로 등록된 클라이언트 수 확인
> pubsub numpat
(integer) 0
psubscribe 명령어
수신할 채널 이름의 패턴을 등록한다. 패턴은 아래와 같은 glob-style을 지원한다.
- '?'는 한 글자를 대치한다.
- h?llo는 hello, hallo, hxllo 같은 것을 의미한다.
- '*'은 공백이나 여러 글자를 대치한다.
- h*llo는 hllo, heeeello 같은 것을 의미한다.
- h[ae]llo는 'a' 나 'e'만 올 수 있다.
- 그래서 hello, hallo는 되고, hillo는 안된다.
# 패턴을 등록하여 수신시작
> psubscribe c*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "c*"
3) (integer) 1
# 패턴 채널을 등록된 채널에는 포함되지 않음
127.0.0.1:6379> pubsub channels
1) "c1"
# 패턴 조회 : 1개 확인
127.0.0.1:6379> pubsub numpat
(integer) 1
# 등록하지 않았던 채널 ch2로 메시지 보냄
> publish ch2 "test 2"
(integer) 1
# 패턴으로 구독 신청한 채널에 메시지가 추가됨
> psubscribe c*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "c*"
3) (integer) 1
1) "pmessage"
2) "c*"
3) "c2"
4) "test 2"
unsubscribe / punsubscribe 명령어
기본적으로 redis-cli에서는 ctrl+c로 구독을 종료할 수 있지만, 별도 클라이언트로 붙었다면 unsubscribe 명령어를 통해 수신을 중단할 수 있다. 마찬가지로 punsubscribe 명령어로 일치하는 패턴의 채널 수신을 중단한다. 채널명을 입력하지 않으면 해당 클라이언트에 등록된 모든 채널을 삭제한다.
> unsubscribe ch1*
1) "unsubscribe"
2) "ch*"
3) (integer) 1
> punsubscribe ch1*
1) "punsubscribe"
2) "ch*"
3) (integer) 1
# 참고자료
https://pompitzz.github.io/blog/Redis/LocalCacheSyncWithRedisPubSub.html
https://www.happykoo.net/@happykoo/posts/81
https://javaengine.tistory.com/entry/Redis-%E2%80%93-spring-data-redis-%EB%B0%9C%ED%96%89%EA%B5%AC%EB%8F%85pubsub-%EB%AA%A8%EB%8D%B8%EC%9D%98-%EA%B5%AC%ED%98%84
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.