RabbitMQ (十) 隊列的參數詳解
代碼中,我們通常這樣聲明一個隊列:
//聲明隊列 channel.QueueDeclare ( queue: QueueName, //隊列名稱 durable: false, //隊列是否持久化.false:隊列在內存中,服務器掛掉後,隊列就沒了;true:服務器重啟後,隊列將會重新生成.註意:只是隊列持久化,不代表隊列中的消息持久化!!!! exclusive: false, //隊列是否專屬,專屬的範圍針對的是連接,也就是說,一個連接下面的多個信道是可見的.對於其他連接時不可見的.連接斷開後,該隊列會被刪除.註意,不是信道斷開,是連接斷開.並且,就算設置成了持久化,也會刪除. autoDelete: true, //如果沒有消費者了,是否自動刪除 (感覺自己沒操作對,這個參數一直沒試驗成功) arguments: null //隊列的配置 );
對於第5個參數: arguments ,
它的類型是一個鍵值對集合 :
它到底有哪些key呢?
我們可以通過 RabbitMQ 的管理頁面看到:
一共10個,鼠標點擊"?",可以看到官方給出的解釋.
Message TTL
官方 : How long a message published to a queue can live before it is discarded (milliseconds). (Sets the "x-message-ttl" argument.)
翻譯 : 一個隊列中的消息,在被丟棄之前能夠存活多少毫秒.( key 為 "x-message-ttl").通俗講就是,隊列中的消息的生存周期,單位毫秒.
測試 :
internal classProgram { private static void Main(string[] args) { Dictionary<string, object> arguments = new Dictionary<string, object> { { "x-message-ttl", 10000 } }; Producer.Send(arguments); Console.ReadKey(); } } public class Producer { private const string QueueName = "test_queue"; public static void Send(IDictionary<string,object> arguments) { using (IConnection connection = ConnectionHelper.GetConnection()) using (IModel channel = connection.CreateModel()) { channel.QueueDeclare(QueueName, false, false, false, arguments); string msg = "hello world "; channel.BasicPublish("", QueueName, null, Encoding.Default.GetBytes(msg)); Console.WriteLine($"{DateTime.Now} : send {msg}"); } } }
我們從管理頁面該隊列的消息概述中可以看出,這條消息只存活了10秒鐘.
為了加以對比,我還另外創建了一個沒有聲明任何參數的隊列:
可以看出,測試的這條隊列的特征(Features)一欄中,被打上了"TTL"標簽.
這裏有個非常重要的知識點需要註意!
隊列一旦聲明,參數將無法更改,添加,刪除,也就是說,對上述"test_queue"隊列進行如下操作都會拋出異常:
- 修改該隊列的 "x-message-ttl" 參數為 "20000" 毫秒 :
Dictionary<string, object> arguments = new Dictionary<string, object> { { "x-message-ttl", 20000 } };
- 試圖通過傳入 null 來刪除該隊列的所有已設置的參數 :
Dictionary<string, object> arguments = null;
- 試圖添加新的參數 :
Dictionary<string, object> arguments = new Dictionary<string, object> { { "x-message-ttl", 10000 } }; arguments.Add("x-expires", 12345);
通通不行!!!
要改變一個隊列的參數,只有兩種辦法:
- 刪除該隊列,重新創建;
- 換個名字,創建一個新的隊列.
Auto expire
官方 : How long a queue can be unused for before it is automatically deleted (milliseconds).(Sets the "x-expires" argument.)
翻譯 : 隊列多長時間(毫秒)沒有被使用(訪問)就會被刪除.換個說法就是,當隊列在指定的時間內沒有被使用(訪問)就會被刪除.
測試 :
private static void Main(string[] args) { Dictionary<string, object> arguments = new Dictionary<string, object> { {"x-message-ttl", 10000},//設置隊列中的消息存活期為 10 秒 { "x-expires", 20000}//設置隊列的存活期 20 秒 }; Producer.Send(arguments); Console.ReadKey(); }
可以看到,隊列特征一欄中,多了一個"Exp"標簽
當然,10秒後,消息會被刪除,20秒後,隊列被刪除
但是,如果我們同時創建一個消費者,監聽該隊列,如下:
public class Consumer { private const string QueueName = "test_queue"; public static void Receive() { IConnection connection = ConnectionHelper.GetConnection(); IModel channel = connection.CreateModel(); EventingBasicConsumer consumer = new EventingBasicConsumer(channel); consumer.Received += (s, e) => { byte[] bytes = e.Body; string str = Encoding.Default.GetString(bytes); Console.WriteLine("consumer receive : " + str); }; channel.BasicConsume(QueueName, true, "", false, false, null, consumer); } }
private static void Main(string[] args) { Dictionary<string, object> arguments = new Dictionary<string, object> { {"x-message-ttl", 10000},//設置隊列中的消息存活期為 10 秒 { "x-expires", 20000}//設置隊列的存活期 20 秒 }; Producer.Send(arguments); Consumer.Receive();//創建一個消費者監聽該隊列 Console.ReadKey(); }
那該隊列永遠不會被刪除.因為雖然它裏面沒有消息,但一直有消費者在使用(訪問)它,所以它不會被刪除.
Max length
官方 : How many (ready) messages a queue can contain before it starts to drop them from its head.(Sets the "x-max-length" argument.)
翻譯 : 隊列可以容納的消息的最大條數,超過這個條數,隊列頭部的消息將會被丟棄.
測試 : 我們設置隊列最多只能容納 1 條消息,然後一次性發送10條,發送完畢後,創建一個消費者去消費,部分代碼如下:
生產者
for (int i = 0; i < 10; i++) { string msg = "hello world " + i; channel.BasicPublish("", QueueName, null, Encoding.Default.GetBytes(msg)); Console.WriteLine($"{DateTime.Now} : send {msg}"); }
private static void Main(string[] args) { Dictionary<string, object> arguments = new Dictionary<string, object> { {"x-message-ttl", 10000},//設置隊列中的消息存活期為 10 秒 { "x-expires", 20000},//設置隊列的存活期 20 秒 {"x-max-length",1 },//設置隊列中的消息的最大條數為 1 條,超過1條,則遵循隊列的"先進先出(丟)"原則. }; Producer.Send(arguments); Thread.Sleep(1000); Consumer.Receive();//創建一個消費者監聽該隊列 Console.ReadKey(); }
運行結果:
可以看到,消費者消費到的是"hello world 9", "hello world 0" - "hello world 8"都被隊列丟棄了.