https://redis.io/docs/latest/develop/interact/pubsub/
SUBSCRIBE, UNSUBSCRIBE, 그리고 PUBLISH는 Publish/Subscribe 메시징 패러다임을 구현합니다. 이는 발신자(게시자)들이 특정 수신자(구독자)에게 메시지를 보내도록 프로그래밍되지 않음을 의미합니다. 대신, 게시된 메시지들은 채널로 분류되며, 어떤 구독자가 있을지(혹은 아예 없을지)에 대한 지식 없이 분류됩니다. 구독자들은 하나 이상의 채널에 관심을 표시하고, 관심 있는 메시지만을 받게 됩니다. 이때, 어떤 게시자가 있는지에 대한 지식도 없습니다. 이러한 게시자와 구독자의 분리는 더 큰 확장성과 더 동적인 네트워크 토폴로지를 가능하게 합니다. 예를 들어, 클라이언트가 "channel11"과 "ch:00"이라는 채널들을 구독하기 위해서는, 채널의 이름을 제공하며 SUBSCRIBE 명령을 실행합니다.
SUBSCRIBE channel11 ch:00
다른 클라이언트가 이 채널들에 보낸 메시지들은 Redis에 의해 모든 구독한 클라이언트들에게 전송됩니다. 구독자들은 메시지들이 발행된 순서대로 메시지를 받게 됩니다.
하나 이상의 채널에 구독한 클라이언트는 명령을 내리면 안 되지만, 다른 채널들에 대해 SUBSCRIBE와 UNSUBSCRIBE를 할 수 있습니다. 구독 및 구독 해제 작업에 대한 응답은 메시지 형태로 전송되므로, 클라이언트는 메시지 유형을 나타내는 첫 번째 요소가 있는 일관된 메시지 스트림을 읽을 수 있습니다. 구독된 RESP2 클라이언트의 맥락에서 허용되는 명령어들은 다음과 같습니다:
그러나, RESP3를 사용하는 경우(HELLO 참조), 클라이언트는 구독 상태에서 어떤 명령이든 내릴 수 있습니다.
redis-cli를 사용할 때 구독 모드에서는 UNSUBSCRIBE나 PUNSUBSCRIBE와 같은 명령어를 사용할 수 없다는 점에 유의해야 합니다. 왜냐하면 redis-cli는 어떠한 명령도 받아들이지 않고 Ctrl-C로만 모드를 종료할 수 있기 때문입니다.
Redis의 Pub/Sub은 최대 한 번 메시지 전달 의미론을 보여줍니다. 이름에서 암시하듯이, 이는 메시지가 전달되면 최대 한 번만 전달된다는 것을 의미합니다. Redis 서버에 의해 메시지가 전송되면, 그 메시지가 다시 전송될 가능성은 없습니다. 구독자가 메시지를 처리할 수 없는 경우(예를 들어, 오류가 발생하거나 네트워크 연결이 끊어진 경우) 그 메시지는 영원히 손실됩니다.
만약 귀하의 애플리케이션이 더 강력한 전달 보장을 요구한다면, Redis Streams에 대해 알아보고 싶을 것입니다. 스트림 내의 메시지들은 지속되며, 최대 한 번뿐만 아니라 최소 한 번 전달 의미론을 모두 지원합니다.
메시지는 세 개의 요소를 가진 배열-응답입니다.
첫 번째 요소는 메시지의 종류입니다:
subscribe: 우리가 성공적으로 구독한 채널을 응답의 두 번째 요소로 나타내며, 세 번째 인자는 현재 구독 중인 채널의 수를 나타냅니다.
unsubscribe: 우리가 성공적으로 구독 해제한 채널을 응답의 두 번째 요소로 나타내며, 세 번째 인자는 현재 구독 중인 채널의 수를 나타냅니다. 마지막 인자가 0일 때, 우리는 더 이상 어떤 채널에도 구독하고 있지 않으며, 클라이언트는 Pub/Sub 상태를 벗어나 어떤 종류의 Redis 명령도 내릴 수 있습니다.
message: 다른 클라이언트가 발행한 PUBLISH 명령의 결과로 받은 메시지입니다. 두 번째 요소는 원본 채널의 이름이며, 세 번째 인자는 실제 메시지 페이로드입니다.
SUBSCRIBE first second
*3
$9
subscribe
$5
first
:1
*3
$9
subscribe
$6
second
:2
이 메시지는 Redis의 구독 명령어인 SUBSCRIBE
를 사용한 예시입니다. 사용자가 Redis 서버에 SUBSCRIBE
명령어로 'first'와 'second'라는 두 채널에 구독을 요청했을 때 서버가 보내는 응답을 나타냅니다.
여기서 각 줄의 의미는 다음과 같습니다:
*3
: 이 메시지는 3개의 요소를 가지고 있음을 나타냅니다 (이 경우 'subscribe', 채널 이름, 그리고 구독 중인 채널의 수).$9
: 다음 문자열의 길이는 9바이트입니다.subscribe
: 이 메시지의 종류를 나타냅니다. 여기서는 구독을 의미합니다.$5
: 다음 문자열의 길이는 5바이트입니다.first
: 사용자가 구독한 첫 번째 채널의 이름입니다.:1
: 사용자가 현재 구독 중인 채널의 총 수입니다. 여기서는 'first' 채널에 대한 구독이 성공적으로 이루어졌음을 나타내며, 이 시점에서 사용자가 구독 중인 채널의 수는 1입니다.그 다음 메시지는 두 번째 채널인 'second'에 대한 구독이 성공적으로 이루어졌음을 나타냅니다:
*3
: 이 메시지 또한 3개의 요소를 가지고 있습니다.$9
: 'subscribe' 문자열의 길이는 같습니다.subscribe
: 이 메시지의 종류입니다.$6
: 다음 문자열의 길이는 6바이트입니다.second
: 사용자가 구독한 두 번째 채널의 이름입니다.:2
: 사용자가 현재 구독 중인 채널의 총 수입니다. 여기서는 'first'와 'second' 두 채널 모두에 대한 구독이 성공적으로 이루어졌음을 나타내며, 이 시점에서 사용자가 구독 중인 채널의 수는 2입니다.이 시점에서, 다른 클라이언트에서 'second'라는 이름의 채널에 대해 PUBLISH 작업을 실행합니다.
> PUBLISH second Hello
이것은 첫 번째 클라이언트가 받는 것입니다.
*3
$7
message
$6
second
$5
Hello
이제 클라이언트는 추가적인 인자 없이 UNSUBSCRIBE 명령어를 사용하여 모든 채널로부터 구독을 해지합니다.
UNSUBSCRIBE
*3
$11
unsubscribe
$6
second
:1
*3
$11
unsubscribe
$5
first
:0
Redis Pub/Sub 구현은 패턴 매칭을 지원합니다. 클라이언트는 glob 스타일 패턴을 구독하여 주어진 패턴과 일치하는 채널 이름으로 보낸 모든 메시지를 받을 수 있습니다.
예를 들어:
PSUBSCRIBE news.*
는 news.art.figurative, news.music.jazz 등의 채널로 보내진 모든 메시지를 받습니다. 모든 glob 스타일 패턴이 유효하므로, 여러 와일드카드가 지원됩니다.
PUNSUBSCRIBE news.*
는 그 패턴으로부터 클라이언트의 구독을 해지합니다. 이 호출로 인해 다른 구독에는 영향을 주지 않습니다.
그러면 해당 패턴으로부터 클라이언트의 구독이 해지됩니다. 이 호출로 인해 다른 구독은 영향을 받지 않습니다.
패턴 매칭의 결과로 받은 메시지는 다른 형식으로 전송됩니다:
SUBSCRIBE와 UNSUBSCRIBE와 유사하게, PSUBSCRIBE와 PUNSUBSCRIBE 명령어는 subscribe와 unsubscribe 메시지 형식과 동일한 형식을 사용하여 시스템이 psubscribe와 punsubscribe 유형의 메시지를 보내는 것으로 승인됩니다.
클라이언트는 발행된 메시지와 일치하는 여러 패턴에 구독되어 있거나, 메시지와 일치하는 패턴과 채널 양쪽에 모두 구독되어 있는 경우, 단일 메시지를 여러 번 받을 수 있습니다. 다음 예시에서 이를 확인할 수 있습니다:
SUBSCRIBE foo
PSUBSCRIBE f*
위 예시에서, 만약 foo 채널로 메시지가 전송된다면, 클라이언트는 두 개의 메시지를 받게 됩니다: 하나는 message 유형이고 다른 하나는 pmessage 유형입니다.
subscribe, unsubscribe, psubscribe 및 punsubscribe 메시지 유형에서 마지막 인자는 여전히 활성화된 구독의 수입니다. 이 숫자는 클라이언트가 여전히 구독하고 있는 채널과 패턴의 총 수입니다. 따라서 클라이언트는 모든 채널과 패턴에서 구독을 해지함으로써 이 수가 0으로 떨어질 때만 Pub/Sub 상태에서 나옵니다.
Redis 7.0부터는 샤딩된 Pub/Sub 기능이 도입되었습니다. 이 기능에서 샤드 채널은 키를 슬롯에 할당하는 데 사용되는 동일한 알고리즘을 사용하여 슬롯에 할당됩니다. 샤드 메시지는 샤드 채널이 해시된 슬롯을 소유한 노드로 보내져야 합니다. 클러스터는 발행된 샤드 메시지가 샤드 내의 모든 노드로 전달되도록 보장합니다. 그래서 클라이언트는 해당 슬롯을 담당하는 마스터나 그 복제본에 연결함으로써 샤드 채널을 구독할 수 있습니다. 이를 구현하기 위해 SSUBSCRIBE, SUNSUBSCRIBE, SPUBLISH가 사용됩니다.
샤딩된 Pub/Sub은 클러스터 모드에서 Pub/Sub의 사용을 확장하는 데 도움을 줍니다. 이는 메시지의 전파를 클러스터의 샤드 내에서 제한함으로써 클러스터 버스를 통해 전달되는 데이터 양을 제한합니다. 이는 각 메시지가 클러스터 내의 각 노드로 전파되는 전역 Pub/Sub에 비해 비교적 데이터 전송량을 줄입니다. 사용자는 더 많은 샤드를 추가함으로써 Pub/Sub 사용을 수평적으로 확장할 수 있습니다.
Pieter Noordhuis는 EventMachine과 Redis를 사용하여 다중 사용자 고성능 웹 채팅을 만드는 훌륭한 예시를 제공했습니다.
모든 수신된 메시지에는 메시지 전달을 유발한 원래의 구독(메시지 유형의 경우 채널, pmessage 유형의 경우 원래 패턴)이 포함되어 있기 때문에, 클라이언트 라이브러리는 해시 테이블을 사용하여 원래의 구독을 콜백(익명 함수, 블록, 함수 포인터일 수 있음)에 바인딩할 수 있습니다.
메시지가 수신되면 O(1) 조회를 수행하여 등록된 콜백에 메시지를 전달할 수 있습니다.