Use RabbitMQ and netrabbitmq in the. NET Environment

Source: Internet
Author: User

Use RabbitMQ and netrabbitmq in the. NET Environment

 

Environment 1

First, because RabbitMQ is compiled using Erlang and needs to run in the Erlang runtime environment, you need to install the Erlang runtime environment before installing the RabbitMQ Server, you can download the installation files for the corresponding platform from the Erlang website. If the runtime environment is not installed, When you install the RabbitMQ Server, you will be prompted to install the Erlang environment first. After installation, make sure that the installation path of Erlang has been registered to the environment variable of the system. After Erlang is installed, the environment is automatically set. If not, follow the settings.

 

Then, go to the RabbitMQ official website to download the RabbitMQ Server program and select the appropriate platform version to download. After the installation is complete, you can start to use it.

Now you can configure the RabbitMQ Server.

First, switch to the RabbitMQ Server installation directory:


There are many batch files under sbin to control RabbitMQ Server.

The simplest way is to make RabbitMQ run in the background as a Windows Service, so we needAdministrator privilegeOpen cmd, switch to the sbin directory, and execute these three commands.

rabbitmq-service install
rabbitmq-service enable
rabbitmq-service start
Now RabbitMQ's server has been started (if the startup fails, please check whether the service has been started after installation, if not, it may be because of the version installation).

Below you can use the rabbitmqctl.bat script under the sbin directory to view and control the server status, and run rabbitmqctl status directly in cmd. If you do n’t see the following result, you need to go to the C: \ Windows directory and copy the .erlang.cookie file to the user directory C: \ Users \ {user name}. This is a cookie file for Erlang, which allows you to perform with Erlang Interaction:

RabbitMQ Server also has a user concept. After installation, use the rabbitmqctl list_users command to see the current users above:

You can use the following commands to add users and set permissions:

rabbitmqctl add_user test 123456
rabbitmqctl set_permissions test ". *" ". *" ". *"
rabbitmqctl set_user_tags test administrator
The above command adds a user named test and sets the password 123456. The following command grants the user test with configuration, read, and write permissions to all message queues, respectively.

Now we can delete the default guest user and use the following command:

rabbitmqctl delete_user guest
If you want to change the password, you can use the following command:

rabbitmqctl change_password {username} {newpassowrd}
2 Get started
To use RabbitMQ in .NET, you need to download the RabbitMQ client assembly. You can download it from the official website. After downloading and decompressing, you can get RabbitMQ.Client.dll, which is the client of RabbitMQ.

Before using RabitMQ, the following basic concepts need to be explained:

RabbitMQ is a message broker. He receives messages from message producers, and then sends messages to message consumers. Between sending and receiving, he can route, cache, and persist according to the set rules.

Generally mentioned RabbitMQ and messages, some proper nouns are used.

Producing means sending. The program that sends the message is a producer. We generally use "P" to represent:
The queue is the name of the mailbox. Messages are transmitted through your application and RabbitMQ, and they can only be stored in a queue. There is no limit to the queue capacity. You can store as many messages as you want-basically an infinite buffer. Multiple producers can send messages to the same queue. Similarly, multiple consumers can get data from the same queue. The queue can be drawn like this (the name of the queue on the picture):
Consuming means the same thing as getting messages. A consumer is a program waiting to get a message. We paint it as "C":
Usually, the message producer, message consumer, and message broker are not on the same machine.

2.1 Hello World
To demonstrate the basic use of RabbitMQ, we send a HelloWorld message and then receive and process it.

First create a console program to send messages to RabbitMQ's message queue, the code is as follows:

First, you need to create a ConnectionFactory and set the target. Since it is on the local machine, set it to localhost. If RabbitMQ is not on the local machine, you only need to set the IP address or machine name of the target machine, and then set the user name test and The password is 123456.

Next, you need to create a Channel. If you want to send a message, you need to create a queue, and then publish the message to this queue. When creating a queue, it will be created only if the queue does not exist on RabbitMQ. The message is transmitted as a binary array, so if the message is a physical object, it needs to be serialized and then converted to a binary array.

Now that the client's sending code has been written, after running, the messages will be posted to the RabbitMQ message queue. Now you need to write the server code to connect to RabbitMQ to get these messages.

Similarly, create a server console application named Receive with the server code as follows:

As with sending, you first need to define the connection and then declare the message queue. To receive a message, you need to define a Consume, then continuously dequeue the message from the message queue, and then process it.

Now the code of the sender and receiver is written. Run the sender and send the message:

 

A message is now sent in the message queue named hello. This message was stored on RabbitMQ's server. Use rabbitmqctl's list_queues to view all the message queues and the number of messages in it. You can see that there is currently only one message queue on Rabbitmq and only one message in it:

rabbitmqctl list_queues
Listing queues ...
hello 1
Now run the receiving program:

You can see that the Hello World sent by the client has been received. Now let's look at the message queue information on RabitMQ:

rabbitmqctl list_queues
Listing queues ...
hello 0
It can be seen that the number of message queues in the hello queue is 0, which means that when the receiving end receives the message, the message is deleted on RabbitMQ.

2.2 work queue
The previous example showed how to send and receive messages to a specified message queue. Now we create a work queue to distribute some time-consuming tasks to multiple workers:

The main idea of work queues (also known as task queues) is to avoid immediate execution and wait for some operations that consume a lot of resources and time to complete. Instead, the task is sent to the queue as a message and processed later. A worker process running in the background will take out the task and process it. When running multiple workers, tasks are shared among them.

This is very useful in web applications, it can handle some complex tasks in short HTTP requests. In some places where the real-time requirements are not too high, we can process other insignificant operations, such as writing logs, etc., after processing the main operations.

ready

In the first part, a string message containing "Hello World!" Is sent. Now send some strings and treat them as complex tasks. The time.sleep () function is used here to simulate a time-consuming task. Add a dot (.) To the string to indicate the complexity of the task. A dot (.) Will take 1 second. For example "Hello ..." will take 3 seconds.

Make some simple adjustments to the previous example of send.cs so that you can send random messages. This program will send tasks to our work queue as scheduled.

static void Main (string [] args)
{
    var factory = new ConnectionFactory ();
    factory.HostName = "localhost";
    factory.UserName = "test";
    factory.Password = "123456";

    using (var connection = factory.CreateConnection ())
    {
        using (var channel = connection.CreateModel ())
        {
            channel.QueueDeclare ("hello", false, false, false, null);
            string message = GetMessage (args);
            var properties = channel.CreateBasicProperties ();
            properties.DeliveryMode = 2;

            var body = Encoding.UTF8.GetBytes (message);
            channel.BasicPublish ("", "hello", properties, body);
            Console.WriteLine ("set {0}", message);
        }
    }

    Console.ReadKey ();
}

private static string GetMessage (string [] args)
{
    return ((args.Length> 0)? string.Join ("", args): "Hello World!");
}
The bold parts have been modified.

Next, we modify the receiving end to let him use the number of seconds in Sleep according to the number of commas in the message:

static void Main (string [] args)
{
    var factory = new ConnectionFactory ();
    factory.HostName = "localhost";
    factory.UserName = "test";
    factory.Password = "123456";

    using (var connection = factory.CreateConnection ())
    {
        using (var channel = connection.CreateModel ())
        {
            channel.QueueDeclare ("hello", false, false, false, null);

            var consumer = new QueueingBasicConsumer (channel);
            channel.BasicConsume ("hello", true, consumer);

            while (true)
            {
                var ea = (BasicDeliverEventArgs) consumer.Queue.Dequeue ();

                var body = ea.Body;
                var message = Encoding.UTF8.GetString (body);

                int dots = message.Split ('.'). Length-1;
                Thread.Sleep (dots * 1000);
                        
                Console.WriteLine ("Received {0}", message);
                Console.WriteLine ("Done");
            }
        }
    }
}
Polling Distribution

One of the benefits of using a work queue is that it can process queues in parallel. If there are many tasks stacked, we only need to add more workers, and the expansion is simple.

Now, we start two receivers, wait for the message, and then start a sender to start sending messages.

 

Under the cmd condition, 5 messages are sent, and the comma after each message indicates the length of time the message needs to be executed to simulate a time-consuming operation.

Then you can see that the two receiving ends received the messages in order:

 

By default, RabbitMQ will distribute each message to the next consumer in order. So the number of messages received by each consumer is roughly average. This method of message distribution is called polling (round-robin).

2.3 Message Response
When dealing with a time-consuming task, you may want to know if the consumers are halfway up and then hang up. In the current code, when RabbitMQ sends a message to consumers, it immediately removes the message from the queue. At this point, if you stop the worker processing the message, the message being processed will be lost. At the same time, all unprocessed messages sent to this worker will be lost.

We don't want to lose any mission messages. If a worker dies, we hope that the message will be resent to other workers.

To prevent message loss, RabbitMQ provides a message response (acknowledgments) mechanism. The consumer will tell RabbitMQ that a message has been received and processed through an ack (response), and then RabbitMQ will release and delete the message.

If the consumer dies, and no response is sent, RabbitMQ will consider the message not completely processed, and then resend it to other consumers. This way, even if workers hang up occasionally, they won't lose messages.

Messages do not have the concept of timeout; when a worker disconnects from it, RabbitMQ will resend the message. In this way, there is no problem when processing a very long message task.

Message response is enabled by default. It was turned off in the previous example using the no_ack = True flag. It's time to remove this flag, and when the worker completes the task, send a response.

channel.BasicConsume ("hello", false, consumer);

while (true)
{
    var ea = (BasicDeliverEventArgs) consumer.Queue.Dequeue ();

    var body = ea.Body;
    var message = Encoding.UTF8.GetString (body);

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

    Console.WriteLine ("Received {0}", message);
    Console.WriteLine ("Done");

    channel.BasicAck (ea.DeliveryTag, false);
}
Now, it can be guaranteed that even if the worker who is processing the message is stopped, these messages will not be lost, and all unanswered messages will be resent to other workers.

A very common mistake is to forget the BasicAck method. This error is very common, but the consequences are serious. When the client exits, the pending messages will be redistributed, but RabitMQ will consume more and more memory because These unanswered messages cannot be released. To debug this case, you can use rabbitmqct to print the messages_unacknoledged field.

rabbitmqctl list_queues name messages_ready messages_unacknowledged
Listing queues ...
hello 0 0
... done.
2.4 message persistence
It has been solved earlier that even if the consumer is down, the task will not be lost, but if the RabbitMQ Server is down, these messages will still be lost.

When RabbitMQ Server shuts down or crashes, the queues and messages stored in it will not be saved by default. If you want RabbitMQ to save messages, you need to set them in two places at the same time: you need to ensure that the queue and messages are persistent.

First, to ensure that RabbitMQ does not lose the queue, so do the following settings:

bool durable = true;
channel.QueueDeclare ("hello", durable, false, false, null);
Although syntactically correct, it is incorrect at this stage because we have previously defined a non-persistent hello queue. RabbitMQ does not allow us to redefine an existing queue of the same name with different parameters. If this is done, an error will be reported. Now, define another queue with a different name:

bool durable = true;
channel.queueDeclare ("task_queue", durable, false, false, null);
queueDeclare This change needs to be set on both the sender and receiver.

It is now guaranteed that the message queue task_queue will not be lost even after RabbitMQ Server restarts. Then you need to ensure that the message is also persistent. This can be achieved by setting IBasicProperties.SetPersistent to true:

var properties = channel.CreateBasicProperties ();
properties.SetPersistent (true);
It should be noted that setting the message to persistent does not completely guarantee that the message will not be lost. Although he told RabbitMQ to save the message to disk, there is still a small time window between when RabbitMQ receives the message and saves it to disk. RabbitMQ probably just saved the message to the cache and didn't write it to disk. Persistence cannot be guaranteed, but it is sufficient for a simple task queue. If you need a strong guarantee for message queue persistence, you can use publisher confirms

2.5 Fair distribution
You may notice that the distribution of messages may not be distributed fairly as we want. For example, for two workers. When the tasks of the odd number of messages are heavy, but the tasks of the even number of messages are light, the odd number of workers always handles the busy state, and the even number of workers always deals with the idle state. But RabbitMQ doesn't know this, he will still distribute the messages in order.

To change this state, we can use the basicQos method and set perfetchCount = 1. This tells RabbitMQ not to send more than one message to a worker at the same time, or in other words. Don't distribute a new message to a worker until he is still processing the message and has not responded to the message. Instead, send this new message to the next less busy worker.

channel.BasicQos (0, 1, false);
2.6 complete example
Now put all this together:

The sender code is as follows:

static void Main (string [] args)
{
    var factory = new ConnectionFactory ();
    factory.HostName = "localhost";
    factory.UserName = "test";
    factory.Password = "123456";

    using (var connection = factory.CreateConnection ())
    {
        using (var channel = connection.CreateModel ())
        {
                   
            bool durable = true;
            channel.QueueDeclare ("task_queue", durable, false, false, null);
                    
            string message = GetMessage (args);
            var properties = channel.CreateBasicProperties ();
            properties.SetPersistent (true);
                  

            var body = Encoding.UTF8.GetBytes (message);
            channel.BasicPublish ("", "task_queue", properties, body);
            Console.WriteLine ("set {0}", message);
        }
    }

    Console.ReadKey ();
}

private static string GetMessage (string [] args)
{
    return ((args.Length> 0)? string.Join ("", args): "Hello World!");
}
The receiving code is as follows:

static void Main (string [] args)
{
    var factory = new ConnectionFactory ();
    factory.HostName = "localhost";
    factory.UserName = "test";
    factory.Password = "123456";

    using (var connection = factory.CreateConnection ())
    {
        using (var channel = connection.CreateModel ())
        {
            bool durable = true;
            channel.QueueDeclare ("task_queue", durable, false, false, null);
            channel.BasicQos (0, 1, false);

            var consumer = new QueueingBasicConsumer (channel);
            channel.BasicConsume ("task_queue", false, consumer);

            while (true)
            {
                var ea = (BasicDeliverEventArgs) consumer.Queue.Dequeue ();

                var body = ea.Body;
                var message = Encoding.UTF8.GetString (body);

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

                Console.WriteLine ("Received {0}", message);
                Console.WriteLine ("Done");

                channel.BasicAck (ea.DeliveryTag, false);
            }
        }
    }
}
Management interface
RabbitMQ also has a management interface, through which you can view the current status of RabbitMQ Server. This interface is provided as a plug-in, and the plug-in is already included when RabbitMQ is installed. What you need to do is to enable the plugin in the RabbitMQ console interface, the command is as follows:

rabbitmq-plugins enable rabbitmq_management
Now, enter http: // server-name: 15672 / server-name in the browser and replace it with the machine address or domain name. If it is local, use localhost directly after inputting, the login interface pops up, and log in with the user we created before .

 .

On this interface you can See all the current status of RabbitMQServer.

Four summary
This article briefly introduces the related concepts of message queues, and introduces the basic principles of RabbitMQ message broker, how to install RabbitMQ on Windows and how to use RabbitMQ in .NET. Message queuing plays an important role in building a distributed system and improving the scalability and responsiveness of the system. I hope this article will help you understand message queuing and how to use RabbitMQ.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.