Using RABBITMQ (GO) in a. NET environment

Source: Internet
Author: User
Tags rabbitmq



In the field of enterprise application system, the communication, integration and integration between different systems will be faced, especially when faced with heterogeneous systems, this kind of distributed call and communication becomes more and more important. Secondly, the system generally will have a lot of real-time requirements are not high but the implementation of more time-consuming place, such as sending text messages, e-mail reminders, update article reading count, record user operation log and so on, if the real-time processing, in the case of a large number of users access, the system pressure is larger.



In the face of these problems, we will generally put these requests in the Message queue processing, heterogeneous systems use messages to communicate. Message delivery seems to be better than file delivery and remote procedure call (RPC) because it has better platform independence and is well-supported for concurrent and asynchronous calls. So if the following occurs in the system:


    • The real-time requirements of the operation are not high, and the tasks that need to be performed are very time consuming;
    • There is integration between heterogeneous systems;


It is generally possible to consider introducing Message Queuing. In the first case, Message Queuing is often selected to handle long-performing tasks. The incoming message queue becomes a buffer for message processing. The asynchronous communication mechanism introduced by Message Queuing allows both the sender and the receiver to continue executing the following code without waiting for the other party to return a successful message, thereby improving the ability to process data. Especially when the traffic volume and data flow are large, it can reduce the load of database processing data by combining the message queue with the background task, and processing the big data by avoiding the peak times.



In a previous article explaining the CQRS pattern, all changes to the state of the system are done through events, typically storing events in the message queue and then processing them uniformly.



This article briefly describes the message Agent tool in RABBITMQ, as well as in the. NET, how to use RABBITMQ.


An environment construction


First, because RABBITMQ is written using Erlang and needs to run on the Erlang runtime environment, you need to install the Erlang Runtime environment before installing RABBITMQ server, and you can download the installation files for the corresponding platform on the Erlang website. If you do not install the runtime environment, you will be prompted to install the Erlang environment before installing RABBITMQ server. After the installation is complete, ensure that the installation path for Erlang is registered to the environment variables of the system. After Erlang is installed, this environment is automatically set, if not, in the administrator environment under the console input, you can also set:


Setx  erlang_home "D:\Program Files (x86) \erl6.3″





Then, go to RABBITMQ official website download RABBITMQ Server service side program, select the appropriate platform version to download. Once the installation is complete, you can start using it.



The RABBITMQ server can now be configured.



First, switch to the installation directory for RABBITMQ server:






There are many batch files under Sbin to control RABBITMQ Server, and of course you can do it directly in the Setup Start menu:






The simplest way is to make RABBITMQ run in the background as a Windows service, so we need to open cmd with Administrator privileges and then switch to the Sbin directory and execute these three commands:


rabbitmq-service install
rabbitmq-service enable
rabbitmq-service start





Now the RABBITMQ server has been started up.



Below you can use the Sbin directory below rabbitmqctl.bat This script to view and control the server state, in CMD directly run Rabbitmqctl status. If you see the following results:






Show that node is not connected, need to go to the C:\Windows directory, copy the. erlang.cookie file to the user directory c:\users\{user name}, this is Erlang's cookie file, allowing interaction with Erlang, Now run the command again and you will get the following information:






RabbitMQ server also has a user concept, after installation, using the Rabbitmqctl list_users command, you can see the above current users:






As you can see, there is now only one role for administrator named Guest user, this is RABBITMQ default for us to create, he has rabbitmq all permissions, general, we need to create a new our own user, set the password, and grant permissions, and set it as an administrator, you can use the following command to do this:


rabbitmqctl  add_user  yy  hello!
rabbitmqctl  set_permissions  yy  ".*"  ".*"  ".*"
rabbitmqctl  set_user_tags yy administrator





One of the above commands adds a user named yy and sets the password hello! , the following command grants user YY the ability to configure, read, and write for 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}
Two start to use


In. NET use RABBITMQ need to download RABBITMQ client assembly, can be downloaded to the official website, download extract can get RabbitMQ.Client.dll, this is RABBITMQ client.



Before using RABITMQ, there are a few basic concepts that need to be explained below:



RABBITMQ is a message agent. He receives messages from the message producer (producers) and sends the message to the message consumer (consumer) between sending and receiving, and he is able to route, cache, and persist according to the rules set.



Generally referred to RABBITMQ and messages, use some proper nouns.


    • Production (producing) means to send. The program that sends the message is a producer (producer). We generally use "P" to denote:




    • The queue is the name of the mailbox. Messages are transmitted through your application and RABBITMQ, and they can only be stored in queues. There is no limit to the queue capacity, and you can store as many messages as you want-essentially an infinite buffer. Multiple producers (producers) can send messages to the same queue, and multiple consumers (consumers) can also fetch data from the same queue. The queue can be drawn like this (the name of the queue on the diagram):




    • Consumption (consuming) and get messages are the same meaning. A consumer (consumer) is a program waiting to get a message. We're painting It "C":





Typically, message producers, message consumers, and message agents 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.






Start by creating a console program to send messages to the RABBITMQ message queue with the following code:


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

        using (var connection = factory.CreateConnection())
        {
            using (var channel = connection.CreateModel())
            {
                channel.QueueDeclare("hello", false, false, false, null);
                string message = "Hello World";
                var body = Encoding.UTF8.GetBytes(message);
                channel.BasicPublish("", "hello", null, body);
                Console.WriteLine(" set {0}", message);
            }
        }
    }


First, you need to create a connectionfactory, set the target, because it is in the local, so set to localhost, if RABBITMQ is not in this machine, only need to set the target machine IP address or machine name, Then set the user name yy and password hello! created earlier.



Next, 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 the queue is created, it is created only if the queue does not exist on RABBITMQ. The message is transmitted as a binary array, so if the message is an entity object, it needs to be serialized and then converted into a binary array.



Now that the client sends the code has been written, after running, the message will be published to RABBITMQ message queue, now need to write the service side of the code to connect to RABBITMQ to get these messages.



Similarly, create a server-side console application called Receive, with the following service-side code:


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

    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);

            Console.WriteLine(" waiting for message.");
            while (true)
            {
                var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();

                var body = ea.Body;
                var message = Encoding.UTF8.GetString(body);
                Console.WriteLine("Received {0}", message);

            }
        }
    }
}


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 and then continuously dequeue the message from the message queue and then process it.



Now the sending and receiving end of the code is written, run the sending side, send messages:






Now, in the message queue named Hello, a message is sent. This message was stored on the RABBITMQ server. With Rabbitmqctl list_queues You can see all the message queues, and the number of messages inside, you can see that there is only one message queue on RABBITMQ, there is only one message:


D:\Program files\rabbitmq server\rabbitmq_server-3.4.2\sbin>rabbitmqctl list_queueslisting queues ... hello   1


Now run the receive-side program, as follows:






As you can see, you have accepted the Hello World sent by the client and now look at the message queue information on RABITMQ:


D:\Program files\rabbitmq server\rabbitmq_server-3.4.2\sbin>rabbitmqctl list_queueslisting queues ... hello   0


As you can see, the number of message queues in this queue is 0, which means that when the receiving end receives the message, the message is deleted from the RABBITMQ.


2.2 Task Force column


The previous example shows how to send and receive messages to a specified message queue. Now we create a task queue to distribute time-consuming tasks to multiple workers (workers):






The main idea of the work queue (working queues, also known as Task Queue task queues) is to avoid immediate execution and wait for some resource-intensive, time-consuming operations to complete. Instead, the task is sent to the queue as a message and processed later. A worker process running in the background takes out the task and processes it. When you run multiple workers (workers), the tasks are shared between them.



This is useful in Web applications, which can handle complex tasks in a short HTTP request. In some places where real-time requirements are not too high, we can deal with the main operations and handle other non-critical operations in the form of messages, such as writing logs and so on.



Get ready



In the first section, a message containing "Hello world!" was sent The string message. Now send some strings and take these strings as complex tasks. This uses the Time.sleep () function to simulate time-consuming tasks. Adding a dot (.) to a string indicates the complexity of the task, and a point (.) will take 1 seconds. For example, "Hello ..." takes 3 seconds.



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


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

    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 part has been modified.



Then we modify the receiver so that he can sleep the number of seconds according to the number of commas in the message:


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

    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");
            }
        }
    }
}


Poll distribution



One advantage of using a work queue is that it can handle queues in parallel. If a lot of tasks are piled up, we just need to add more workers (workers), and the extension is simple.



Now, let's start with two receivers, wait for the message to be accepted, and start sending a message by starting a Send side.






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



You can then see that the two receiving end received the message in turn:






By default, RABBITMQ distributes each message sequentially to the next consumer in order. So the number of messages received by each consumer is roughly average. The way this message is distributed is called polling (Round-robin).


2.3 Message response


When dealing with a more time-consuming task, you might want to know if the consumer (consumers) is running halfway down. In the current code, when RABBITMQ sends a message to the consumer (consumers), the message is immediately removed from the queue. At this point, if the worker (worker) handling the message is stopped, the message being processed is lost. At the same time, all messages sent to this worker are not processed and will be lost.



We don't want to lose any task messages. If a worker is hung up, we want the message to be sent back to another worker (worker).



To prevent message loss, RABBITMQ provides a message response (acknowledgments) mechanism . The consumer will pass an ACK (response) telling RABBITMQ that a message has been received and processed, and then RABBITMQ will release and delete the message.



If the consumer (consumer) hangs up and does not send a response, RABBITMQ will assume that the message is not fully processed and then resend it to the other consumer (consumer). This way, even if the worker (workers) hangs up occasionally, it will not lose the message.



The message is not a time-out concept, and RABBITMQ will resend the message when the worker disconnects from it. This will not be a problem when dealing with a very long-time messaging task.



Message responses are turned on by default. In the previous example, the No_ack=true logo was used to turn it off. It's time to remove the identity, and when the worker finishes 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); }


It is now guaranteed that even if the worker who is processing the message is stopped, the messages will not be lost and all messages that are not answered will be resent to the other worker.



A common mistake is to forget the Basicack method, a common mistake, but with serious consequences. When the client exits, the pending message is redistributed, but RABITMQ consumes more and more memory because the messages that are not answered cannot be freed. To debug this case, you can print the Messages_unacknoledged field using RABBITMQCT.


Rabbitmqctl list_queues name Messages_ready messages_unacknowledgedlisting queues ... hello    0       0...done.
2.4 Persistence of messages


The front is done. Even if the consumer is down, the task will not be lost, but if RABBITMQ server is stopped, the messages will still be lost.



When RABBITMQ Server shuts down or crashes, the queues and messages stored inside are not saved by default. If you want RABBITMQ to save the message, you need to set it up in two places at the same time: you need to make sure that both the queue and the message are persisted.



First, make sure that the RABBITMQ does not lose the queue, so do the following:


BOOL durable = True;channel. Queuedeclare ("Hello", durable, false, false, NULL);


Although syntactically correct, it is not correct at this stage because we have previously defined a non-persisted hello queue. RABBITMQ does not allow us to redefine a queue with the same name that already exists with different parameters, if this will cause an error. 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 at the same time as the sending and receiving ends.



Task_queue is now guaranteed. This message queue is not lost even after the RABBITMQ server restarts. You then need to ensure that the message is also persisted, which can be achieved by setting Ibasicproperties.setpersistent to true:


var properties = Channel. Createbasicproperties ();p roperties. Setpersistent (TRUE);


It is important to note that setting the message to persistent does not guarantee that the message is not lost. Although he told RABBITMQ to save the message to disk, there was still a small window of time between RABBITMQ receiving the message and saving it to disk. RabbitMQ may simply save the message to the cache and not write it to disk. Persistence cannot be guaranteed, but it is sufficient for a simple task queue. If you need strong guarantees for Message Queuing persistence, you can use Publisher confirms


2.5 Fair Distribution


You may notice that the distribution of the message may not be as fair as we want it to be. For example, for two workers. When the task of an odd number of messages is heavier, but an even number of message tasks are lighter, an odd number of workers always handle the busy state, while an even number of workers always handle the idle state. But Rabbitmq didn't know that, and he would still distribute the message on average in turn.



To change this state, we can use the Basicqos method to set the Perfetchcount=1. This tells RABBITMQ not to send more than 1 messages to a worker at the same time, or in other words. Do not distribute new messages to a worker while it is still processing the message and does not respond to the message. Instead, send the new message to the next less busy worker.



2.6 Full Instance


Now put all this together:



The send-side code is as follows:


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

    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 receive-side code is as follows:


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

    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);
            }
        }
    }
}
Three management interface


RABBITMQ also has a management interface that allows you to view the current state of the RABBITMQ Server, which is provided as a plug-in, and has been brought to the plug-in when the RABBITMQ is installed. What needs to be done is to enable the plugin in the RABBITMQ console interface, with the following command:


Rabbitmq-plugins Enable Rabbitmq_management





Now, enter http://server-namein the browser, 15672/server-name to the machine address or domain name, if local, use localhost directly (RabbitMQ 3.0 before the version port number is 55672) after the input, the login screen pops up, using the user we created earlier to log in.



.



In this interface, you can see all the states of the current rabbitmqserver.


Iv. Summary


This article briefly describes the concepts of Message Queuing and describes the fundamentals of the RABBITMQ message broker and how to install RABBITMQ on Windows and how to use RABBITMQ in. Net. Message Queuing plays an important role in building distributed systems and improving the scalability and responsiveness of the system, and hopefully this article will help you understand Message Queuing and how to use RABBITMQ.


Five reference documents
    1. Http://www.infoq.com/cn/articles/message-based-distributed-architecture
    2. Http://www.rabbitmq.com/getstarted.html
    3. Http://www.codethinked.com/using-rabbitmq-with-c-and-net
    4. Http://www.infoq.com/cn/articles/AMQP-RabbitMQ
    5. Http://www.infoq.com/cn/articles/ebay-scalability-best-practices


Using RABBITMQ (GO) in a. NET environment


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.