订阅者模块

1. 客户端实现思路

在 RabbitMQ 中,提供服务的是信道,因此在客户端的实现中,弱化了 Client 客户端的概念,也就是说在 RabbitMQ 中并不会向用户展示网络通信的概念出来,而是以一种提供服务的形式来体现。

其实现思想类似于普通的功能接口封装,一个接口实现一个功能,接口内部完成向客户端请求的过程,但是对外并不需要体现出客户端与服务端通信的概念,用户需要什么服务就调用什么接口就行。

基于以上的思想,客户端的实现共分为四大模块:

  • 订阅者模块:
    • 一个并不直接对用户展示的模块,其在客户端体现的作用就是对于角色的描 述,表示这是一个消费者
  • 信道模块
    • 一个直接面向用户的模块,内部包含多个向外提供的服务接口,用户需要什么服务,调用对应接口即可○ 其包含交换机声明/删除,队列声明/删除,绑定/解绑,消息发布/确认,订阅/解除订阅等服务。
  • 连接模块
    • 这是唯一能体现出网络通信概念的一个模块了,它向用户提供的功能就是用于打开/关闭信道。
  • 异步线程模块
    • 虽然客户端部分,并不对外体现网络通信的概念,但是本质上内部还是包含有网络通信的,因此既然有网络通信,那么就必须包含有一个网络通信 IO 事件监控线程模块,用于进行客户端连接的 IO 事件监控,以便于在事件出发后进行 IO 操作。
    • 其次,在客户端部分存在一个情况就是,当一个信道作为消费者而存在的时 候,服务端会向信道推送消息,而用户这边需要对收到的消息进行不同的业务处理,而这个消息的处理需要一个异步的工作线程池来完成。
    • 因此异步线程模块包含两个部分:
      • 客户端连接的 IO 事件监控线程
      • 推送过来的消息异步处理线程

基于以上模块,实现一个客户端的流程也就比较简单了

  1. 实例化异步线程对象
  2. 实例化连接对象
  3. 通过连接对象,创建信道
  4. 根据信道获取自己所需服务
  5. 关闭信道
  6. 关闭连接

2. 订阅者模块

与服务端,并无太大差别,客户端这边虽然订阅者的存在感微弱了很多,但是还是有的,当进行队列消息订阅的时候,会伴随着一个订阅者对象的创建,而这个订阅者对象有以下几个作用:

  • 描述当前信道订阅了哪个队列的消息。
  • 描述了收到消息后该如何对这条消息进行处理。
  • 描述收到消息后是否需要进行确认回复。

所以,订阅者模块并不直接对用户展示,它是对消费者角色的描述。当用户通过信道订阅队列时,内部会创建一个订阅者对象,该对象负责处理从服务端推送过来的消息。

设计要点:

  1. 每个订阅者对应一个消费者标签(consumer_tag)和一个队列(queue_name)。
  2. 订阅者需要提供一个回调函数,当消息到达时,异步线程模块会调用这个回调函数。
  3. 订阅者可能支持自动确认或手动确认模式。

因此订阅者信息:

  • 订阅者标识
  • 订阅队列名
  • 是否自动确认标志
  • 回调处理函数(收到消息后该如何处理的回调函数对象)
cpp 复制代码
#ifndef __M_CONSUMER_H__
#define __M_CONSUMER_H__
#include "../mqcommon/logger.hpp"
#include "../mqcommon/helper.hpp"
#include "../mqcommon/msg.pb.h"
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>
#include <vector>
#include <functional>


namespace rabbitmq
{
    using ConsumerCallback = std::function<void(const std::string, const BasicProperties *bp, const std::string)>;
    struct Consumer
    {
        using ptr = std::shared_ptr<Consumer>;
        std::string _tag; //消费者标识
        std::string _qname; //消费者订阅的队列名称
        bool _auto_ack; //自动确认标志
        ConsumerCallback _callback;

        Consumer()
        {
            DLOG("new Consumer: %p", this);
        }
        Consumer(const std::string &ctag, const std::string &queue_name,  bool ack_flag, const ConsumerCallback &cb)
            :_tag(ctag), _qname(queue_name), _auto_ack(ack_flag), _callback(std::move(cb)) 
        {
            DLOG("new Consumer: %p", this);
        }
        ~Consumer() 
        {
            DLOG("del Consumer: %p", this);
        }
    };
}

#endif
相关推荐
止语Lab3 天前
一次 goroutine 泄漏:pprof 说有 10 万个 goroutine,但问题不在 channel
rabbitmq
JLWcai2025100918 天前
铸造领域树脂砂轮|金利威多场景解决方案,20 + 配方覆盖全需求
mongodb·zookeeper·eureka·spark·rabbitmq·memcached·storm
风吹夏回18 天前
RabbitMQ 核心术语 + Python pika 方法完整讲解
分布式·python·rabbitmq
风吹夏回18 天前
RabbitMQ 三种模式入门:HelloWorld、WorkQueue、PubSub
分布式·rabbitmq·ruby
cheems952718 天前
[RabbitMQ高级特性] 消息确认机制:从 Ready / Unacked 到 basicAck、basicReject、basicNack 的底层拆解
分布式·rabbitmq·ruby
半夜修仙19 天前
延迟队列的介绍及常见问题
java·数据库·中间件·rabbitmq
Solis程序员19 天前
Raft:分布式系统的定海神针
java·分布式·kafka·rabbitmq·agent·raft
手握风云-19 天前
一条消息的旅程:RabbitMQ 学习与实践(一)
中间件·rabbitmq
Zyangxsir19 天前
RabbitMQ 核心概念以及Java(Spring Boot)实战用法的整理
java·spring boot·后端·rabbitmq·java-rabbitmq
南部余额20 天前
RabbitMQ 进阶:延迟队列完全指南
java·分布式·spring·rabbitmq