首页 新闻 会员 周边

RabbitMQ.Client

0
悬赏园豆:15 [已解决问题] 解决于 2016-12-09 11:25

最近学习RabbitMQ C# 遇到几个问题请教一下大神

Publish/Subscribe

Routing

Topics

这三中队列消费消息问题,

官方给出的消费消息的方法中间都有一个获取与Exchange随机绑定的队列名称,
var queueName = channel.QueueDeclare().QueueName;

然后消费这个队列的消息消费队列中的消息
var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body;
                var message = Encoding.UTF8.GetString(body);
                var routingKey = ea.RoutingKey;
                Console.WriteLine(" [x] Received '{0}':'{1}'",
                                  routingKey,
                                  message);
            };

例如:Publish/Subscribe 模式


如果C1 断掉之后重新消费怎么保证消费的是之前的队列
而不会消费到其他队列中未消费的消息

PS: 使用事件驱动

问题补充:

var factory = new ConnectionFactory() { HostName = "localhost" };
        using(var connection = factory.CreateConnection())
        using(var channel = connection.CreateModel())
        {
            channel.ExchangeDeclare(exchange: "logs", type: "fanout");

            var queueName = channel.QueueDeclare().QueueName;
            channel.QueueBind(queue: queueName,
                              exchange: "logs",
                              routingKey: "");

            Console.WriteLine(" [*] Waiting for logs.");

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body;
                var message = Encoding.UTF8.GetString(body);
                Console.WriteLine(" [x] {0}", message);
            };
            channel.BasicConsume(queue: queueName,
                                 noAck: true,
                                 consumer: consumer);

            Console.WriteLine(" Press [enter] to exit.");
            Console.ReadLine();
        }

官方给出的示例

我就是不明白 如果消费者在线的时候消费完一波消息后,再次登录重新消费,怎么保持和之前消费的队列一样

挨踢新手的主页 挨踢新手 | 初学一级 | 园豆:71
提问于:2016-12-08 17:21
< >
分享
最佳答案
0

我一般用的时候都是先在mq上建好exchange和队列及其关系。代码中仅处理发送消费的场景。

收获园豆:15
Daniel Cai | 专家六级 |园豆:10424 | 2016-12-08 17:31

我就是不明白 如果消费者在线的时候消费完一波消息后,再次登录重新消费,怎么保持就是之前消费的队列

是不是我对 消息队列的理解有问题。

挨踢新手 | 园豆:71 (初学一级) | 2016-12-09 09:40

@挨踢新手: 我的意思是我在使用前,直接在mq上建好相关信息,比如

exchange1--->queue1

生产者直接在代码中往exchange1中发数据,消费者直接从queue1中取数据。你所谓的再登录是指消费者重启么?如果是这个也没任何关系,反正queue1这个作为常量已经写到配置或代码中了,所以每次连mq都是从相同地方取数据。

Daniel Cai | 园豆:10424 (专家六级) | 2016-12-09 10:00

@Daniel Cai: 

关于消费者消费消息,官方给出的示例中

工作队列是你说的这样的逻辑

channel.QueueDeclare(queue: "task_queue",
                                 durable: true,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);

            channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);

            Console.WriteLine(" [*] Waiting for messages.");

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body;
                var message = Encoding.UTF8.GetString(body);
                Console.WriteLine(" [x] Received {0}", message);

                int dots = message.Split('.').Length - 1;
                Thread.Sleep(dots * 1000);

                Console.WriteLine(" [x] Done");

                channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
            };
可是消息模式分多种的:
Publish/Subscribe

channel.ExchangeDeclare(exchange: "logs", type: "fanout");

            var queueName = channel.QueueDeclare().QueueName;
            channel.QueueBind(queue: queueName,
                              exchange: "logs",
                              routingKey: "");

            Console.WriteLine(" [*] Waiting for logs.");

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body;
                var message = Encoding.UTF8.GetString(body);
                Console.WriteLine(" [x] {0}", message);
            };
            channel.BasicConsume(queue: queueName,
                                 noAck: true,
                                 consumer: consumer);


Routing、Topics(类似消息推送,只是需要绑定Bind)

这种消费方式好像没有直接指导具体的队列上。

也就是说获取了 与指定交换机按照指定的路由绑定在一起的队列集合,中的随机一个队列进行消费,

也就是这段代码 var queueName = channel.QueueDeclare().QueueName;

这个才是消费者最终消费的队列。

不知道我理解的是否正确。

 

那么问题来了:

如果是工作队列,那就我目前看到官方的资料,消费者是不关心交换机和路由的 而是直接指定某个队列。

但是如果是Publish/Subscribe、Routing、Topics模式的 好像不直接指定队列名称而是按某种交换机路由约定,获得一个随机队列进行消费。这个时候如果消费者重启,那么消费的队列还是之前消费的队列吗?

 

我对消息队列理解不深刻,请多多赐教

 

 

挨踢新手 | 园豆:71 (初学一级) | 2016-12-09 10:27

@挨踢新手: rabbitmq中exchange三种模式,fanout(字面理解,所以你消费方创建一个队列并绑定到这个exchange后是可以接受到消息,就算你下线等你再次上线创建新队列时也可以收到从这个exchange发送过来的消息,但之前的消息则不在你新建的这个队列中,这种模式下routingkey被忽略)

direct(字面理解,指哪打哪,根据routingkey走)

topic(这个可实现的功能较前者多,包括根据routingkey做匹配进行路由)

在消费者看来,的确它只关心队列,前面乱七八糟的都不归它管,而且这个跟push/pull模式也没关系

在生产者看来,严格意义上我感觉是全部都要关系,走哪个exchange,怎么路由,到哪个队列。

 

你的实例代码刚好也就是fanout的一种形式,根据上面所说的,这个q和exchange只需要存在绑定关系即可,后面发送过来的消息会发送到这个exchange下绑定的队列中。

Daniel Cai | 园豆:10424 (专家六级) | 2016-12-09 10:46

@Daniel Cai: 

多谢你耐心回复。

按照你这样的方式,是不是说任何消费者都是只关心队列。而不关心Exchange,routingKey

一个消费者消费消息时必须指定一个队列名?以确定消费的是哪个队列。

那我是不是应该这样理解。

简单的消息队列是不是针对每个消费者都会有唯一的一个队列。

当一个队列被多个消费者消费的时候,队列中的消息一般应该只被消费一次。对吧。

例如:消息推送模式,是不是每个消费者都会有单独的一个队列。

不知道我理解的正确吗?

 

 

另外

var queueName = channel.QueueDeclare().QueueName;

官方示例的这段代码会生成

amq.gen-7L4bwv57iTlt_JIuirn_aQ 类似于这样子的随机队列名

这个队列有什么用处吗?

 

挨踢新手 | 园豆:71 (初学一级) | 2016-12-09 11:00

@挨踢新手: 消费者只关心队列,这个和你不关心你买的手机具体怎么制造的一样的逻辑。

消费者当然需要指明队列名,我都不知道你要买啥我给你什么?

消息队列不一定是一个队列一个消费者,一般会有多个消费者挂在同一队列后,一般用于处理异步请求并方便横向扩展。

一个队列中消息被消费时正常情况下只被一个消费者消费,但是如果你队列设为需要ack而你消费者没有正常ack的话这条消息是可以被其他消费者消费的。但autoack方式下是不存在这个问题。

 

这种随机名字就是你建的队列的名称啊,比如在你前面例子的fanout模式下,你消费者主动创建队列并完成绑定,那么你就需要考虑如果后面服务重启这种情况,你应该将这个q的name持久化下来避免重启后丢消息(消息实际上没有丢,只是你重新创建了队列,新队列中只有新接收到的消息,而之前的消息会在你fanout对应的队列中继续留存)。

Daniel Cai | 园豆:10424 (专家六级) | 2016-12-09 11:10

明白了,
万分感谢

挨踢新手 | 园豆:71 (初学一级) | 2016-12-09 11:25
其他回答(1)
0

每个队列是不是有个token 消费者是通过token去消费对应的队列。

~扎克伯格 | 园豆:1923 (小虾三级) | 2016-12-08 17:36

队列Token?我没找到有这方面的说明呀。官方提供的和再网上搜索的,都没有提到过这个呀。

我也是学习RabbitMQ的,有没有这方面的资料?

支持(0) 反对(0) 挨踢新手 | 园豆:71 (初学一级) | 2016-12-09 08:39
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册