十年河東,十年河西,莫欺少年窮
學無止境,精益求精
先盜用一張圖,介紹下RabbitMQ的架構圖
簡介
Producer : 生產者
channel : 通信信道,節約Tcp鏈接資源
Broker : MQ Server接點,做集羣用的
VirtualHost : 虛擬機,一個RabbitMQ中可以有多個虛擬機,我們可以通過RabbitMQ提供的可視化網站中創建,虛擬機中可以有多個隊列,可以將虛擬機分配不同的用戶角色
Exchange : 交換機 ,代碼中可以不指定交換機,不指定交換機時,交換機名稱要和隊列名稱一致。
Queue : 消息隊列
Consumer : 消費者
RabbitMQ 使用的端口如下:
生產者
關於RabbitMQ的安裝請參考:windows環境下,RabbitMQ 安裝教程
1、新建一個控制檯程序,Nuget引入RabbitMQ.Client
2、創建如下生產者程序
using RabbitMQ.Client; using System; using System.Collections.Generic; using System.Text; namespace RabbitMqProducer { class Program { static void Main(string[] args) { ConnectionFactory factory = new ConnectionFactory(); factory.HostName = "127.0.0.1"; //主機名 factory.UserName = "guest";//使用的用戶 factory.Password = "guest";//用戶密碼 factory.Port = 5672;//端口號 factory.VirtualHost = "/"; //虛擬主機 factory.MaxMessageSize = 1024; //消息最大字節數 using (var connection = factory.CreateConnection())//連接服務器,即正在創建終結點。 { //rabbitMQ 基於信道進行通信,因此,我們需要實例化信道Channel using (var channel = connection.CreateModel()) { //queue : 隊列名稱 //durable : 是否持久化消息,如果設置爲true 則會將詳細存儲在磁盤中 //exclusive : 是否設置爲獨佔隊列,意思是指只能有一個消費者,設置爲false,可以有多個消費者同時消費 //autoDelete : 是否是臨時隊列,臨時隊列會隨着消費者斷開連接時自動刪除 //arguments : arguments 裏面有很多屬性可以設置,例如隊列過期時間等 //QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary<string, object> arguments); Dictionary<string, object> arguments = new Dictionary<string, object>(); arguments.Add("x-expires", 45 * 1000); // 隊列在一定時間內沒被使用,則刪除 arguments.Add("x-message-ttl", 45 * 1000);//隊列中消息的存活1時間 channel.QueueDeclare("RabbitMQ", false, false, false, arguments);//創建一個名稱爲kibaqueue的消息隊列 var properties = channel.CreateBasicProperties(); properties.DeliveryMode = 1; //deliveryMode: 1(nopersistent)非持久化,2(persistent)持久化 properties.Priority = 9;//消息的優先級 值越大 優先級越高 properties.ContentType = "text/plain";//消息的內輸出格式 properties.Expiration = (60 * 1000).ToString(); //消息的過期時間爲60秒 var messages = "I am RabbitMQ"; //傳遞的消息內容 //exchange 交換機,如果使用默認的交換機,那麼routingKey要和隊列的名稱一致 //routingKey:路由 //basicProperties : 用於基礎屬性設置 ///BasicPublish(this IModel model, string exchange, string routingKey, IBasicProperties basicProperties, ReadOnlyMemory<byte> body); channel.BasicPublish("", "RabbitMQ", properties, Encoding.UTF8.GetBytes(messages)); //生產消息 } } Console.Read(); } } }
上述代碼中需要重點介紹如下注釋:QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary<string, object> arguments);
//queue : 隊列名稱 //durable : 是否持久化消息,如果設置爲true 則會將詳細存儲在磁盤中 //exclusive : 是否設置爲獨佔隊列,意思是指只能有一個消費者,設置爲false,可以有多個消費者同時消費 //autoDelete : 是否是臨時隊列,臨時隊列會隨着消費者斷開連接時自動刪除 //arguments : arguments 裏面有很多屬性可以設置,例如隊列過期時間等 //QueueDeclareOk QueueDeclare(string queue, bool durable, bool exclusive, bool autoDelete, IDictionary<string, object> arguments);
autoDelete 設置爲true後,隊列就變成了臨時隊列,也就是自動刪除的隊列
自動刪除隊列和普通隊列在使用上沒有什麼區別,唯一的區別是,當消費者斷開連接時,隊列將會被刪除。自動刪除隊列允許的消費者沒有限制,也就是說當這個隊列上最後一個消費者斷開連接纔會執行刪除。
自動刪除隊列只需要在聲明隊列時,設置屬性auto-delete標識爲true即可。系統聲明的隨機隊列,缺省就是自動刪除的。
exclusive 設置爲TRUE時,隊列就成了單消費者隊列
普通隊列允許的消費者沒有限制,多個消費者綁定到多個隊列時,RabbitMQ會採用輪詢進行投遞。如果需要消費者獨佔隊列,在隊列創建的時候,設定屬性exclusive爲true。
durable 設置爲true 代表永久隊列,消息會被存儲到磁盤中
持久化隊列和非持久化隊列的區別是,持久化隊列會被保存在磁盤中,固定並持久的存儲,當Rabbit服務重啓後,該隊列會保持原來的狀態在RabbitMQ中被管理,而非持久化隊列不會被保存在磁盤中,Rabbit服務重啓後隊列就會消失。
非持久化比持久化的優勢就是,由於非持久化不需要保存在磁盤中,所以使用速度就比持久化隊列快。即是非持久化的性能要高於持久化。而持久化的優點就是會一直存在,不會隨服務的重啓或服務器的宕機而消失。
在聲明隊列時,將屬性durable設置爲“false”,則該隊列爲非持久化隊列,設置成“true”時,該隊列就爲持久化隊列
自動過期隊列
指隊列在超過一定時間沒使用,會被從RabbitMQ中被刪除。什麼是沒使用?
一定時間內沒有Get操作發生
沒有Consumer連接在隊列上
特別的:就算一直有消息進入隊列,也不算隊列在被使用。
通過聲明隊列時,設定x-expires參數即可,單位毫秒。
關於arguments中的參數,我們可以通過RabbitMQ提供的工具中查看,如下圖:
含義如下
信道的基礎屬性,代碼部分如下:
var properties = channel.CreateBasicProperties();
屬性如下
contentType:消息的內容類型,如:text/plain contentEncoding:消息內容編碼 headers:設置消息的header,類型爲Map<String,Object> deliveryMode:1(nopersistent)非持久化,2(persistent)持久化 priority:消息的優先級 correlationId:關聯ID replyTo:用於指定回覆的隊列的名稱 expiration:消息的失效時間 messageId:消息ID timestamp:消息的時間戳 type:類型 userId:用戶ID appId:應用程序ID custerId:集羣ID
以上就是兔子MQ生產者代碼構建過程中的詳細細節
消費者
代碼如下
using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Collections.Generic; using System.Text; namespace RabbitMqConsumer { class Program { static void Main(string[] args) { ConnectionFactory factory = new ConnectionFactory(); factory.HostName = "127.0.0.1"; //主機名 factory.UserName = "guest";//使用的用戶 factory.Password = "guest";//用戶密碼 factory.Port = 5672;//端口號 factory.VirtualHost = "/"; //虛擬主機 factory.MaxMessageSize = 1024; //消息最大字節數 //創建連接 var connection = factory.CreateConnection(); //創建通道 var channel = connection.CreateModel(); //事件基本消費者 EventingBasicConsumer consumer = new EventingBasicConsumer(channel); //接收到消息事件 consumer.Received += (ch, ea) => { var message = Encoding.UTF8.GetString(ea.Body.ToArray()); Console.WriteLine($"收到消息: {message}"); //確認該消息已被消費 channel.BasicAck(ea.DeliveryTag, false); }; //啓動消費者 channel.BasicConsume("RabbitMQ", false, consumer); Console.WriteLine("消費者已啓動"); Console.ReadKey(); channel.Dispose(); connection.Close(); } } }
@天才臥龍的博客