RabbitMQ series of C# (3)--Work Queues

work queue

Usage scenario: Work Queue is used to process a large number of time-consuming tasks. Instead of waiting for the task to be processed and consuming a lot of CPU resources, it is better to return immediately and hand it over to the proxy worker to process the message.

Endurance

The code of the producer and the consumer is basically the same as that of the Publish-Consumer in the previous section , the only difference is the parameter adjustment of the configuration item. code show as below:

using System;
using System.Collections.Generic;
using System.Text;
using RabbitMQ.Client;

namespace NewTask
{
    class NewTask
    {
        public static void Main(string[] args)
        {
            var factory = new ConnectionFactory() { HostName = "localhost" };
            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                channel.QueueDeclare(queue: "task_queue",
                                     durable: true,
                                     exclusive: false,
                                     autoDelete: false,
                                     arguments: null);
                //At this point we're sure that the task_queue queue won't be lost even if RabbitMQ restarts. Now we need to mark our messages as persistent - by setting IBasicProperties.SetPersistent to true.
                var properties = channel.CreateBasicProperties();
                //properties.SetPersistent(true);//此方法已经过时:“这种设置方法已经被摒弃,现在使用持久化属性取代它”
                properties.Persistent = true;//取代上面的写法

                ...
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

Queue persistence is declared through durable: true, and the queue still exists after the service restarts, but if it is declared as an exclusive queue exclusive: true, it is not affected by persistence, and the connection is disconnected and removed.
Message persistence is set by properties.Persistent = true, provided that the queue is persistent, otherwise the message will definitely be lost after the service is down, because the message carrier queue is gone.

message receipt

In some scenarios with high accuracy requirements, we may need to receive the ack returned from the consumer before deleting from the queue.

  • If the ack is not received , the message will stay in the queue until the connection is disconnected, at which time it will be sent to the next consumer in the cluster for processing;
  • What about queues that never stop? Then, of course, the message will stay in the queue forever until the memory is exhausted, which is not a good thing, so the consumer must remember to handle exceptions and finally send a receipt;
  • If there is no cluster , the connection will be reopened and sent to the original consumer again;

Talk back to the worker

In my opinion, worker is just another name for consumer, but its function is more special. As mentioned at the beginning of this article, the consumer basically declares the queue, registers and accepts events. These steps are the same, but the configuration items are different. , look at the configuration of the worker:

using System;
using System.Text;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;

namespace Worker
{
    class Worker
    {
        public static void Main()
        {
            var factory = new ConnectionFactory() { HostName = "localhost" };
            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                channel.QueueDeclare(queue: "task_queue",
                                     durable: true,
                                     exclusive: false,
                                     autoDelete: false,
                                     arguments: null);

                channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);//prefetchCount:This tells RabbitMQ not to give more than one message to a worker at a time. Or, in other words, don't dispatch a new message to a worker until it has processed and acknowledged the previous one. Instead, it will dispatch it to the next worker that is not still busy(Fair dispatch(公平分发):它会选择空闲的worker去处理消息,适用于对性能敏感的场景;Round-robin dispatching(轮循分发):不解释)

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

                var consumer = new EventingBasicConsumer(channel);
                channel.BasicConsume(queue: "task_queue",
                                     noAck: false,
                                     consumer: consumer);
                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);//用以处理完毕后发送ack通知服务端
                };

                Console.WriteLine(" Press [enter] to exit.");
                Console.ReadLine();
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

注意这句代码以及注释:channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false) 下面是BasicQops方法的说明:

BasicQops用于设置任务分发,只有收到前一条消息的回执才会发给当前worker,否则轮循下一个worker。如果所有worker都是忙碌,那么建议添加worker设备。

说明worker的特点就是单线程处理消息,如果处于忙碌状态(未发送回执),则不会收到队列推送的消息。

小结:通过队列声明durable: true设置队列持久化,并无多大意义,只是为消息持久化做铺垫;消息持久化通过properties.Persistent = true或者properties.DeliveryMode = 2进行设置;消息回执需要注意处理消费端的代码保证ack总是返回给队列;worker实际上就是一种单线程机制的消费者。

就到这供自己学习,欢迎指正批评!!!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326075143&siteId=291194637