Publish / Subscribe란 특정한 주제에 대해서 구독하면, 발행자가 메시지를 보냈을 때 구독한 모든 클라이언트에게 메시지를 전송하는 것을 의미한다.
예를 들어, 인스타나 유튜브에서 팔로우, 구독 버튼을 누르면 발행자로부터 알림을 우리가 받는 것과 같은 원리이다.
위와 같은 구조로 이루어져 있다.
펍섭 구조에서 사용되는 큐를 Topic이라고 일반적으로 부른다.
https://redis.io/docs/interact/pubsub/
공식 문서를 해석해서 공부했다.
Redis의 Pub/Sub은 최대 1회 메시지 전달 의미 체계를 가진다. 이름에서 알 수 있듯이, 메시지가 한 번만 전달된다는 의미이다. Redis 서버에서 메시지를 보내면, 그것이 다시 보내질 가능성은 없다. 만약 구독자가 메시지를 처리할 수 없는 경우(예를 들어, 네트워크 연결 끊김 등) 메시지는 영원히 손실된다.
메시지는 세 가지 요소로 구성된 배열 응답이다.
첫 번째 요소는 메시지의 종류이다.
subscribe: 이것은 응답의 두 번째 요소로 제공된 채널을 성공적으로 구독했음을 의미한다. 세 번째 인수는 현재 구독 중인 채널의 수를 나타낸다.
unsubscribe: 이것은 응답의 두 번째 요소로 제공된 채널의 구독을 성공적으로 취소했음을 의미한다. 세 번째 인수는 현재 구독 중인 채널 수를 나타낸다.
message: 다른 클라이언트가 발행한 publish 명령의 결과로 수신된 메시지이다. 두 번째 요소는 원래 채널의 이름이고, 세 번째 인수는 실제 메시지 페이로드이다.
Pub/Sub은 key 공간과 그 어떠한 관련이 없다. 데이터 베이스 번호를 포함한 어떠한 수준에서도 간섭하지 않도록 만들어졌다.
ch1
채널을 리스닝하는 클라이언트를 두개 만들고, ch1
채널에 메시지를 날리는 클라이언트를 가정하고 진행했다.
따로 채널을 만드는 과정 없이, 바로 subscribe
하고, 메시지를 날리고 싶은 곳에 publish
하면 된다.
사용법은 정말 간단하고 이론도 간단해서 더 할게 없어보인다. 이것을 응용하면, 레디스 내에 Lists
자료구조를 만들어 놓고 그것을 큐로 이용해서 큐 내에 아이템이 들어왔다는 이벤트를 Producer
가 발생시키고 Consumer
가 그것을 가져가게 하는 Producer Consumer
패턴을 만들 수도 있을 것 같다.
그런데 사용하면서 느낀거지만, 레디스의 Pub/Sub
방식은 1회성에 불과하고 전달 여부를 확인하지 않기 때문에 만약에 모든 Consumer
또는 Subscriber
가 메시지를 전부 받지 못한다면 문제가 발생할 것이라는 생각이 들었다. 간단하지만 간단한 만큼 제공해주는 기능이 없는 것 같다.
아이템의 소비/수신 여부를 확인해주는 기능이 있는 다른 것은 없을까? 한번 찾아봐야겠다. 이 질문 그대로 chatgpt에게 물어보자.
네, Pub/Sub
방식에서는 메시지의 소비 여부를 확인하기가 어렵습니다. 그러나 메시지 소비 여부를 확인할 수 있는 메시징 시스템도 있습니다. 예를 들면 Apache Kafka가 그러한 메시징 시스템 중 하나입니다.
Kafka는 메시지를 토픽으로 구분하고, 각각의 메시지에 대한 오프셋(Offset)을 관리합니다. 이를 통해 어떤 메시지까지 소비되었는지 추적할 수 있습니다. 또한, 소비자(Consumer) 그룹을 이용하여 여러 개의 컨슈머가 특정 토픽의 메시지를 나눠서 소비할 수 있습니다.
따라서 Apache Kafka를 사용하면 메시지의 소비 여부를 추적하고 관리할 수 있습니다. 이외에도 RabbitMQ와 같은 메시징 시스템도 소비자와 프로듀서 간의 메시지 전달 상태를 관리할 수 있는 기능을 제공합니다.
역시 사람 생각은 다 똑같나보다 이미 다 만들어져있다.. Kafka
와 RabbitMQ
가 이러한 기능을 제공한다고 한다. 어디서 많이 들어본 애들인데 다시 만나니 반갑다..
읽다가 offset
으로 소비 여부를 파악한다고 하는데, 어떻게 offset
으로 소비 여부를 관리/추적하는지 궁금해져서 다시 물어봤다.
Apache Kafka에서는 각 메시지에 대한 오프셋(Offset)을 관리하여 소비 여부를 추적합니다. 간단히 설명하면, 오프셋은 특정 토픽 내의 파티션(partition)에 저장된 메시지의 위치를 나타냅니다. 소비자(Consumer)가 메시지를 소비하면 해당 메시지의 오프셋이 증가하게 됩니다.
다음은 Kafka에서 소비자가 오프셋을 통해 메시지를 추적하는 간단한 과정입니다:
토픽 및 파티션 할당: 각 소비자는 특정 토픽과 파티션에 할당됩니다.
오프셋 관리: 소비자는 각 파티션 내의 다음으로 소비할 메시지의 오프셋을 추적합니다.
메시지 소비: 소비자는 해당 오프셋의 메시지를 소비하고, 오프셋을 증가시킵니다.
오프셋 커밋: 소비자는 소비한 메시지의 오프셋을 주기적으로 또는 특정 이벤트 후에 커밋합니다. 이로써 소비자는 어디까지 메시지를 소비했는지를 추적할 수 있습니다.
이러한 오프셋 기반의 추적은 메시지의 소비 여부를 정확하게 파악할 수 있게 해줍니다. 또한, 소비자 그룹을 이용하면 여러 소비자 간에 작업을 나누어 처리하고, 효율적으로 메시지를 소비할 수 있습니다.
메시지를 소비하면 클라이언트(소비자)가 오프셋을 하나 증가시켜서 관리한다고 이해했다. 설명을 들으니 정말 간단하다.
이런 기능을 하는 기술들도 한번 실습하면서 공부해봐야겠다. 다음 프로젝트 때 유용하게 써먹을 수 있을 것이다. 둘 다 공부하긴 그렇고, 둘 중 하나만 고르라면 뭐가 더 학습하기 용이할까? 이것도 gpt한테 물어보도록 하자
RabbitMQ
와Kafka
의 장단점과 러닝 커브가 낮고 학습에 용이한 것 추천해줘
RabbitMQ
와 Kafka
는 모두 메시지 브로커 시스템이지만, 몇 가지 차이점이 있습니다. 각각의 장단점을 살펴보고, 러닝 커브가 낮고 학습에 용이한 측면을 중심으로 비교해 보겠습니다.
장점:
1. 유연성과 다양한 프로토콜 지원: RabbitMQ는 다양한 프로토콜을 지원하며, AMQP(Advanced Message Queuing Protocol)를 기반으로 한다.
2. 가볍고 빠른 메시지 전달: 단일 브로커 구조로 가볍고, 높은 성능의 메시지 전달을 제공한다.
3. 큐, 라우팅, 교환기 등의 기능: 다양한 메시지 패턴을 지원하며, 유연한 메시지 라우팅이 가능하다.
단점:
1. 확장성 한계: RabbitMQ는 확장성 면에서 한계가 있을 수 있으며, 대규모 데이터 스트림 처리에는 적합하지 않을 수 있다.
장점:
1. 고성능 및 확장성: 대용량 데이터 스트림을 처리하는 데 특화되어 있으며, 수평 확장이 용이하다.
2. 내결함성: 분산 아키텍처로 구성되어 있어 높은 내결함성을 제공한다.
3. 로그 기반의 저장: 메시지를 영속적으로 저장하고, 이를 기반으로한 데이터 리플레이가 가능하다.
단점:
1. 러닝 커브: Kafka는 분산 시스템이므로 설정 및 운영에 대한 이해가 필요하며, 초기 학습이 다소 어려울 수 있다.
따라서 프로젝트의 요구 사항과 개발자의 경험 수준을 고려하여 RabbitMQ를 추천합니다.
엄청나게 많은 데이터 스트림을 처리해야 하면 Kafka
를 이용하는 것이 맞는 것 같고 빠르게 배우고 메시지의 규모가 그렇게 크지 않은 곳에는 RabbitMQ
를 사용하는 것이 적절할 것 같다. 다음 시간에는 RabbitMQ
를 사용하여 실습을 해봐야겠다.