rabbitMq-----消费者管理模块

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

只有订阅客户端订阅了一个队列消息后,他才是一个消费者,而消费者存在的意义是,当这个队列上有消息的时候我们呢需要给订阅了这个队列的客户端推送消息,也就需要获取客户端的连接,所以我们呢可以通过消费者来找到对应的连接来进行消息的推送。


消费者字段

消费者订阅的队列名称,消费者也是按照队列问单元进行管理的。

消费者标志,标志消费者唯一性

自动应答标志,客户端在订阅队列消息时可以进行设置,如果为true,则将消息推送给消费客户端后不需要等待应带,直接将消息进行删除。

还有一个回调函数。当队列有消息到来时,就需要选择一个队列消费者进行消费,那么如何进行消费呢?就是调用这个回调函数。这个函数的逻辑固定,就是通过连接发送消息。是由我们broker服务器设置的。

cpp 复制代码
//当队列收到一条消息后,需要选择一个消费者进行消费,那么如何消费呢?
    //就是调用这个回调函数,其内部逻辑是:找到消费者对应的连接,将消息发送给客户端。
    using ConsumerCallBack = std::function<void(const std::string&,const BasicProperties *,const std::string &)>;
    struct Consumer
    {
        using ptr = std::shared_ptr<Consumer>;
        std::string _qname; //消费者订阅的队列名称
        std::string _ctag;  //消费者标识
        bool _auto_ack;  //自动应答标志
        ConsumerCallBack _cb;
}

消费者内存管理类

消费者是以队列为单位进行管理的,我们使用一个vector管理订阅该队列的消费者。

目的是方便进行rr轮转。

cpp 复制代码
class QueueConsumer
    {
    private:
        std::string _qname; //队列名称
        std::mutex _mutex;  
        uint64_t _rr_sep;   //轮转序号
        std::vector<Consumer::ptr> _consumers;
    }

新增/删除消费者

构造一个消费者对象进行添加。删除就是遍历删除。

cpp 复制代码
 //新增一个消费者 
        Consumer::ptr create(const std::string &qname,const std::string &ctag,bool auto_ack,const ConsumerCallBack &cb){
   //1.加锁
   std::unique_lock<std::mutex> lock(_mutex);

   //2.判断消费者是否存在
   for(auto &cons : _consumers){
       if(cons->_ctag == ctag){
           return cons;
       }
   }

   //3.创建消费者并添加管理
   Consumer::ptr csp = std::make_shared<Consumer>(qname,ctag,auto_ack,cb);
   _consumers.push_back(csp);

   return csp;
}
//删除一个消费者:取消订阅、信道关闭、连接关闭的时候删除
void remove(const std::string &ctag){
   //1.加锁
   std::unique_lock<std::mutex> lock(_mutex);

   //2.遍历删除
   for(auto it = _consumers.begin(); it != _consumers.end(); ++it){
       if((*it)->_ctag == ctag){
           _consumers.erase(it);
           return;
       }
   }

   return;
}

选择一个消费者,rr轮转的思想。

在收到一条消息后,会进行路由匹配,获取到匹配成功的队列。然后把消息推送到队列上,同时取出一个消费者进行消费。

cpp 复制代码
 //选择一个消费者,rr轮转的思想
 Consumer::ptr choose(){
     //1.加锁
     std::unique_lock<std::mutex> lock(_mutex);

     //如果没有消费者,则返回空对象
     if(_consumers.size() == 0){
         return Consumer::ptr();
     }
     //2.获取当前选择的消费者下标
     uint64_t idx = _rr_sep % _consumers.size();
     _rr_sep++;

     //3.获取对象并返回
     return _consumers[idx];
 }

总的消费者管理类

这个类才是对外提供的类。

就是用一个哈希表把队列名称和消费者管理对象关联起来进行管理。

有一initQueueConsumer函数就是用力啊初始化队列消费者管理对象的,需要判断当前以存在的队列,来进行初始化对应的消费者管理类。

cpp 复制代码
 class ConsumerManager
    {
    private:    
        std::mutex _mutex;
        std::unordered_map<std::string,QueueConsumer::ptr> _qconsumers;
    public:
    using ptr = std::shared_ptr<ConsumerManager>;
        ConsumerManager(){}
        //初始化队列消费者管理
        void initQueueConsumer(const std::string &qname){
            //1. 加锁
            std::unique_lock<std::mutex> lock(_mutex);
            //2. 重复判断
            auto it = _qconsumers.find(qname);
            if (it != _qconsumers.end()) {
                return ;
            }
            //3. 新增
            auto qconsumers = std::make_shared<QueueConsumer>(qname);
            _qconsumers.insert(std::make_pair(qname, qconsumers));
        }
}

删除队列消费者管理类对象,当一个队列删除时,就选哦删除这个队列的消费者管理类对象,

cpp 复制代码
 //删除队列消费者管理
        void destroyQueueConsumer(const std::string &qname){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _qconsumers.find(qname);
            if (it == _qconsumers.end()) {
                return ;
            }
            _qconsumers.erase(it);
        }

创建/删除指定队列的消费者管理类对象中的消费者

根据队列的名称,选择指定的消费者管理类对象进行一个操作即可,

cpp 复制代码
Consumer::ptr create(const std::string &qname,const std::string &ctag,bool auto_ack,const ConsumerCallBack &cb){
   QueueConsumer::ptr qcp;
   {
       std::unique_lock<std::mutex> lock(_mutex);

       auto it = _qconsumers.find(qname);
       if(it == _qconsumers.end()){
           ELOG("没有找到队列 %s 的消费者管理句柄!",qname.c_str());
           return Consumer::ptr();
       }

       qcp = it->second;
   }

   //这个create不需要我们这里的mutex保护,他有自己的mutex
   return qcp->create(qname,ctag,auto_ack,cb);
}
void remove(const std::string &ctag,const std::string &qname){
   QueueConsumer::ptr qcp;
   {
       std::unique_lock<std::mutex> lock(_mutex);

       auto it = _qconsumers.find(qname);
       if(it == _qconsumers.end()){
           ELOG("没有找到队列 %s 的消费者管理句柄!",qname.c_str());
           return ;
       }

       qcp = it->second;
   }

   qcp->remove(ctag);
}

选择指定队列的消费者管理类对象中的消费者

cpp 复制代码
Consumer::ptr choose(const std::string &qname){
   QueueConsumer::ptr qcp;
   {
       std::unique_lock<std::mutex> lock(_mutex);

       auto it = _qconsumers.find(qname);
       if(it == _qconsumers.end()){
           ELOG("没有找到队列 %s 的消费者管理句柄!",qname.c_str());
           return Consumer::ptr();
       }

       qcp = it->second;
   }

   return qcp->choose();
}
相关推荐
dengjiayue2 小时前
消息队列(kafka 与 rocketMQ)
分布式·kafka·rocketmq
东阳马生架构4 小时前
zk基础—4.zk实现分布式功能二
分布式
ChinaRainbowSea4 小时前
8. RabbitMQ 消息队列 + 结合配合 Spring Boot 框架实现 “发布确认” 的功能
java·spring boot·分布式·后端·rabbitmq·java-rabbitmq
IT成长日记5 小时前
【Kafka基础】Kafka高可用集群:2.8以下版本超详细部署指南,运维必看!
分布式·zookeeper·kafka·集群部署
码界筑梦坊5 小时前
基于Spark的酒店数据分析系统
大数据·分布式·python·信息可视化·spark·毕业设计·个性化推荐
山海不说话5 小时前
从零搭建微服务项目Pro(第7-1章——分布式雪花算法)
分布式·算法·spring·微服务·架构
掘金-我是哪吒5 小时前
分布式微服务系统架构第95集:基于 Redisson 延迟队列,springboot,springcloud启动过程,策略模式
spring boot·分布式·spring cloud·微服务·系统架构
郭涤生5 小时前
第九章:可靠通信_《凤凰架构:构建可靠的大型分布式系统》
笔记·分布式·架构·系统架构
Plus-ultra6 小时前
Java面试34-Kafka的零拷贝原理
java·分布式·面试·kafka
DemonAvenger6 小时前
深入理解WaitGroup与并发任务编排:从原理到实战的最佳实践
分布式·go·代码规范