RAbbit mq在.net中的運用

在企業(yè)應(yīng)用系統(tǒng)領(lǐng)域颊咬,會面對不同系統(tǒng)之間的通信肪笋、集成與整合,尤其當面臨異構(gòu)系統(tǒng)時呜袁,這種分布式的調(diào)用與通信變得越發(fā)重要敌买。其次,系統(tǒng)中一般會有很多對實時性要求不高的但是執(zhí)行起來比較較耗時的地方阶界,比如發(fā)送短信虹钮,郵件提醒聋庵,更新文章閱讀計數(shù),記錄用戶操作日志等等芙粱,如果實時處理的話祭玉,在用戶訪問量比較大的情況下,對系統(tǒng)壓力比較大春畔。


面對這些問題脱货,我們一般會將這些請求,放在消息隊列中處理律姨;異構(gòu)系統(tǒng)之間使用消息進行通訊振峻。消息傳遞相較文件傳遞與遠程過程調(diào)用(RPC)而言,似乎更勝一籌择份,因為它具有更好的平臺無關(guān)性扣孟,并能夠很好地支持并發(fā)與異步調(diào)用。所以如果系統(tǒng)中出現(xiàn)了如下情況:


對操作的實時性要求不高荣赶,而需要執(zhí)行的任務(wù)極為耗時凤价;


存在異構(gòu)系統(tǒng)間的整合;


一般的可以考慮引入消息隊列拔创。對于第一種情況料仗,常常會選擇消息隊列來處理執(zhí)行時間較長的任務(wù)。引入的消息隊列就成了消息處理的緩沖區(qū)伏蚊。消息隊列引入的異步通信機制,使得發(fā)送方和接收方都不用等待對方返回成功消息格粪,就可以繼續(xù)執(zhí)行下面的代碼躏吊,從而提高了數(shù)據(jù)處理的能力。尤其是當訪問量和數(shù)據(jù)流量較大的情況下帐萎,就可以結(jié)合消息隊列與后臺任務(wù)比伏,通過避開高峰期對大數(shù)據(jù)進行處理,就可以有效降低數(shù)據(jù)庫處理數(shù)據(jù)的負荷疆导。


在前面的一篇講解CQRS模式的文章中赁项,所有的對系統(tǒng)的狀態(tài)的更改都是通過事件來完成,一般的將事件存儲到消息隊列中澈段,然后進行統(tǒng)一的處理悠菜。


本文簡單介紹在RabbitMQ這一消息代理工具,以及在.NET中如何使用RabbitMQ.


一 環(huán)境搭建


首先败富,由于RabbitMQ使用Erlang編寫的悔醋,需要運行在Erlang運行時環(huán)境上,所以在安裝RabbitMQ Server之前需要安裝Erlang 運行時環(huán)境兽叮,可以到Erlang官網(wǎng)下載對應(yīng)平臺的安裝文件芬骄。如果沒有安裝運行時環(huán)境猾愿,安裝RabbitMQ Server的時候,會提示需要先安裝Erlang環(huán)境账阻。 安裝完成之后蒂秘,確保已經(jīng)將Erlang的安裝路徑注冊到系統(tǒng)的環(huán)境變量中。安裝完Erlang之后淘太,這個環(huán)境會自動設(shè)置姻僧,如果沒有,在administrator環(huán)境下在控制臺下面輸入琴儿,也可以設(shè)置:


Setx? ERLANG_HOME “D:\Program Files (x86)\erl6.3″

然后段化,去RabbitMQ官網(wǎng)下載RabbitMQ Server服務(wù)端程序,選擇合適的平臺版本下載造成。安裝完成之后显熏,就可以開始使用了。


現(xiàn)在就可以對RabbitMQ Server進行配置了晒屎。


首先喘蟆,切換到RabbitMQ Server的安裝目錄:


在sbin下面有很多batch文件,用來控制RabbitMQ Server鼓鲁,當然您也可以直接在安裝開始菜單中來執(zhí)行相應(yīng)的操作:


最簡單的方式是使RabbitMQ以Windows Service的方式在后臺運行蕴轨,所以我們需要以管理員權(quán)限打開cmd,然后切換到sbin目錄下骇吭,執(zhí)行這三條命令即可:


rabbitmq-service installrabbitmq-service enablerabbitmq-service start

現(xiàn)在RabbitMQ的服務(wù)端已經(jīng)啟動起來了橙弱。


下面可以使用sbin目錄下面的rabbitmqctl.bat這個腳本來查看和控制服務(wù)端狀態(tài)的,在cmd中直接運行rabbitmqctl status燥狰。如果看到以下結(jié)果:


顯示node沒有連接上棘脐,需要到C:\Windows目錄下,將.erlang.cookie文件龙致,拷貝到用戶目錄下 C:\Users\{用戶名}蛀缝,這是Erlang的Cookie文件,允許與Erlang進行交互目代,現(xiàn)在重復(fù)運行剛才的命令就會得到如下信息:


RabbitMQ Server上面也有用戶概念屈梁,安裝好之后,使用rabbitmqctl list_users命令榛了,可以看到上面目前的用戶:


可以看到在讶,現(xiàn)在只有一個角色為administrator的名為guest的用戶,這個是RabbitMQ默認為我們創(chuàng)建的霜大,他有RabbitMQ的所有權(quán)限真朗,一般的,我們需要新建一個我們自己的用戶僧诚,設(shè)置密碼遮婶,并授予權(quán)限蝗碎,并將其設(shè)置為管理員,可以使用下面的命令來執(zhí)行這一操作:


rabbitmqctl? add_user? yy? hello!rabbitmqctl? set_permissions? yy? <span rabbitmqctl? set_user_tags yy administrator

上面的一條命令添加了一個名為yy的用戶旗扑,并設(shè)置了密碼hello蹦骑!,下面的命令為用戶yy分別授予對所有消息隊列的配置臀防、讀和寫的權(quán)限眠菇。


現(xiàn)在我們可以將默認的guest用戶刪掉,使用下面的命令即可:


rabbitmqctl delete_user guest

如果要修改密碼袱衷,可以使用下面的命令:


rabbitmqctl change_password {username}? {newpassowrd}

二 開始使用


在.NET中使用RabbitMQ需要下載RabbitMQ的客戶端程序集捎废,可以到官網(wǎng)下載,下載解壓后就可以得到RabbitMQ.Client.dll致燥,這就是RabbitMQ的客戶端登疗。


在使用RabitMQ之前,需要對下面的幾個基本概念說明一下:


RabbitMQ是一個消息代理嫌蚤。他從消息生產(chǎn)者(producers)那里接收消息辐益,然后把消息送給消息消費者(consumer)在發(fā)送和接受之間,他能夠根據(jù)設(shè)置的規(guī)則進行路由脱吱,緩存和持久化智政。


一般提到RabbitMQ和消息,都用到一些專有名詞箱蝠。


生產(chǎn)(Producing)意思就是發(fā)送续捂。發(fā)送消息的程序就是一個生產(chǎn)者(producer)。我們一般用"P"來表示:


隊列(queue)就是郵箱的名稱宦搬。消息通過你的應(yīng)用程序和RabbitMQ進行傳輸牙瓢,它們只能存儲在隊列(queue)中。 隊列(queue)容量沒有限制床三,你要存儲多少消息都可以——基本上是一個無限的緩沖區(qū)。多個生產(chǎn)者(producers)能夠把消息發(fā)送給同一個隊列杨幼,同樣撇簿,多個消費者(consumers)也能從同一個隊列(queue)中獲取數(shù)據(jù)。隊列可以畫成這樣(圖上是隊列的名稱):


消費(Consuming)和獲取消息是一樣的意思差购。一個消費者(consumer)就是一個等待獲取消息的程序四瘫。我們把它畫作"C":


通常,消息生產(chǎn)者欲逃,消息消費者和消息代理不在同一臺機器上找蜜。


2.1 Hello World


為了展示RabbitMQ的基本使用,我們發(fā)送一個HelloWorld消息稳析,然后接收并處理洗做。


首先創(chuàng)建一個控制臺程序弓叛,用來將消息發(fā)送到RabbitMQ的消息隊列中,代碼如下:


? ? string[] args)? ? {? ? ? ? ConnectionFactory();? ? ? ? factory.HostName = <span ;? ? ? ? factory.UserName = <span ;? ? ? ? factory.Password = <span ;? ? ? ? var connection = factory.CreateConnection())? ? ? ? {? ? ? ? ? ? var channel = connection.CreateModel())? ? ? ? ? ? {? ? ? ? ? ? ? ? channel.QueueDeclare(null);? ? ? ? ? ? ? ? <span ;? ? ? ? ? ? ? ? Encoding.UTF8.GetBytes(message);? ? ? ? ? ? ? ? channel.BasicPublish(null, body);? ? ? ? ? ? ? ? <span , message);? ? ? ? ? ? }? ? ? ? }? ? }

首先诚纸,需要創(chuàng)建一個ConnectionFactory撰筷,設(shè)置目標,由于是在本機畦徘,所以設(shè)置為localhost毕籽,如果RabbitMQ不在本機,只需要設(shè)置目標機器的IP地址或者機器名稱即可井辆,然后設(shè)置前面創(chuàng)建的用戶名yy和密碼hello关筒!。

緊接著要創(chuàng)建一個Channel杯缺,如果要發(fā)送消息蒸播,需要創(chuàng)建一個隊列,然后將消息發(fā)布到這個隊列中夺谁。在創(chuàng)建隊列的時候廉赔,只有RabbitMQ上該隊列不存在,才會去創(chuàng)建匾鸥。消息是以二進制數(shù)組的形式傳輸?shù)睦匀绻⑹菍嶓w對象的話,需要序列化和然后轉(zhuǎn)化為二進制數(shù)組勿负。

現(xiàn)在客戶端發(fā)送代碼已經(jīng)寫好了馏艾,運行之后,消息會發(fā)布到RabbitMQ的消息隊列中奴愉,現(xiàn)在需要編寫服務(wù)端的代碼連接到RabbitMQ上去獲取這些消息琅摩。

同樣,創(chuàng)建一個名為Receive的服務(wù)端控制臺應(yīng)用程序锭硼,服務(wù)端代碼如下:

string[] args){? ? ConnectionFactory();? ? factory.HostName = <span ;? ? factory.UserName = <span ;? ? factory.Password = <span ;? ? var connection = factory.CreateConnection())? ? {? ? ? ? var channel = connection.CreateModel())? ? ? ? {? ? ? ? ? ? channel.QueueDeclare(null);? ? ? ? ? ? QueueingBasicConsumer(channel);? ? ? ? ? ? channel.BasicConsume(true, consumer);? ? ? ? ? ? <span );? ? ? ? ? ? true)? ? ? ? ? ? {? ? ? ? ? ? ? ? BasicDeliverEventArgs)consumer.Queue.Dequeue();? ? ? ? ? ? ? ? var body = ea.Body;? ? ? ? ? ? ? ? Encoding.UTF8.GetString(body);? ? ? ? ? ? ? ? <span , message);? ? ? ? ? ? }? ? ? ? }? ? }}

和發(fā)送一樣房资,首先需要定義連接,然后聲明消息隊列檀头。要接收消息轰异,需要定義一個Consume,然后從消息隊列中不斷Dequeue消息暑始,然后處理搭独。

現(xiàn)在發(fā)送端和接收端的代碼都寫好了,運行發(fā)送端廊镜,發(fā)送消息:

現(xiàn)在牙肝,名為hello的消息隊列中,發(fā)送了一條消息。這條消息存儲到了RabbitMQ的服務(wù)器上了配椭。使用rabbitmqctl 的list_queues可以查看所有的消息隊列虫溜,以及里面的消息個數(shù),可以看到颂郎,目前Rabbitmq上只有一個消息隊列吼渡,里面只有一條消息:

D:\Program Files\RabbitMQ Server\rabbitmq_server-3.4.2\sbin>rabbitmqctl list_queuesListing queues ...hello? 1

現(xiàn)在運行接收端程序,如下:

可以看到乓序,已經(jīng)接受到了客戶端發(fā)送的Hello World寺酪,現(xiàn)在再來看RabitMQ上的消息隊列信息:

D:\Program Files\RabbitMQ Server\rabbitmq_server-3.4.2\sbin>rabbitmqctl list_queuesListing queues ...hello? 0

可以看到,hello這個隊列中的消息隊列個數(shù)為0替劈,這表示寄雀,當接收端,接收到消息之后陨献,RabbitMQ上就把這個消息刪掉了盒犹。

2.2 工作隊列

前面的例子展示了如何往一個指定的消息隊列中發(fā)送和收取消息。現(xiàn)在我們創(chuàng)建一個工作隊列(work queue)來將一些耗時的任務(wù)分發(fā)給多個工作者(workers):

工作隊列(work queues, 又稱任務(wù)隊列Task Queues)的主要思想是為了避免立即執(zhí)行并等待一些占用大量資源眨业、時間的操作完成急膀。而是把任務(wù)(Task)當作消息發(fā)送到隊列中,稍后處理龄捡。一個運行在后臺的工作者(worker)進程就會取出任務(wù)然后處理卓嫂。當運行多個工作者(workers)時,任務(wù)會在它們之間共享聘殖。

這個在網(wǎng)絡(luò)應(yīng)用中非常有用晨雳,它可以在短暫的HTTP請求中處理一些復(fù)雜的任務(wù)。在一些實時性要求不太高的地方奸腺,我們可以處理完主要操作之后餐禁,以消息的方式來處理其他的不緊要的操作,比如寫日志等等突照。

準備

在第一部分帮非,發(fā)送了一個包含“Hello World!”的字符串消息。現(xiàn)在發(fā)送一些字符串讹蘑,把這些字符串當作復(fù)雜的任務(wù)末盔。這里使用time.sleep()函數(shù)來模擬耗時的任務(wù)。在字符串中加上點號(.)來表示任務(wù)的復(fù)雜程度衔肢,一個點(.)將會耗時1秒鐘庄岖。比如"Hello..."就會耗時3秒鐘豁翎。

對之前示例的send.cs做些簡單的調(diào)整角骤,以便可以發(fā)送隨意的消息。這個程序會按照計劃發(fā)送任務(wù)到我們的工作隊列中。

string[] args){? ? ConnectionFactory();? ? factory.HostName = <span ;? ? factory.UserName = <span ;? ? factory.Password = <span ;? ? var connection = factory.CreateConnection())? ? {? ? ? ? var channel = connection.CreateModel())? ? ? ? {? ? ? ? ? ? channel.QueueDeclare(null);? ? ? ? ? ? string message = GetMessage(args);? ? ? ? ? ? var properties = channel.CreateBasicProperties();? ? ? ? ? ? properties.DeliveryMode = 2;? ? ? ? ? ? Encoding.UTF8.GetBytes(message);? ? ? ? ? ? channel.BasicPublish(<span , properties, body);? ? ? ? ? ? <span , message);? ? ? ? }? ? }? ? Console.ReadKey();}string[] args){? ? <span );}

加粗部分是經(jīng)過修改過了的邦尊。

接著我們修改接收端背桐,讓他根據(jù)消息中的逗點的個數(shù)來Sleep對應(yīng)的秒數(shù):

string[] args){? ? ConnectionFactory();? ? factory.HostName = <span ;? ? factory.UserName = <span ;? ? factory.Password = <span ;? ? var connection = factory.CreateConnection())? ? {? ? ? ? var channel = connection.CreateModel())? ? ? ? {? ? ? ? ? ? channel.QueueDeclare(null);? ? ? ? ? ? QueueingBasicConsumer(channel);? ? ? ? ? ? channel.BasicConsume(true, consumer);? ? ? ? ? ? true)? ? ? ? ? ? {? ? ? ? ? ? ? ? BasicDeliverEventArgs)consumer.Queue.Dequeue();? ? ? ? ? ? ? ? var body = ea.Body;? ? ? ? ? ? ? ? Encoding.UTF8.GetString(body);? ? ? ? ? ? ? ? '.').Length - 1;? ? ? ? ? ? ? ? Thread.Sleep(dots * 1000);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? <span , message);? ? ? ? ? ? ? ? <span );? ? ? ? ? ? }? ? ? ? }? ? }}

輪詢分發(fā)

使用工作隊列的一個好處就是它能夠并行的處理隊列。如果堆積了很多任務(wù)蝉揍,我們只需要添加更多的工作者(workers)就可以了链峭,擴展很簡單。

現(xiàn)在又沾,我們先啟動兩個接收端弊仪,等待接受消息,然后啟動一個發(fā)送端開始發(fā)送消息杖刷。

在cmd條件下励饵,發(fā)送了5條消息,每條消息后面的逗點表示該消息需要執(zhí)行的時長滑燃,來模擬耗時的操作役听。

然后可以看到,兩個接收端依次接收到了發(fā)出的消息:

默認表窘,RabbitMQ會將每個消息按照順序依次分發(fā)給下一個消費者典予。所以每個消費者接收到的消息個數(shù)大致是平均的。 這種消息分發(fā)的方式稱之為輪詢(round-robin)乐严。

2.3 消息響應(yīng)

當處理一個比較耗時得任務(wù)的時候瘤袖,也許想知道消費者(consumers)是否運行到一半就掛掉。在當前的代碼中麦备,當RabbitMQ將消息發(fā)送給消費者(consumers)之后孽椰,馬上就會將該消息從隊列中移除。此時凛篙,如果把處理這個消息的工作者(worker)停掉黍匾,正在處理的這條消息就會丟失。同時呛梆,所有發(fā)送到這個工作者的還沒有處理的消息都會丟失锐涯。

我們不想丟失任何任務(wù)消息。如果一個工作者(worker)掛掉了填物,我們希望該消息會重新發(fā)送給其他的工作者(worker)纹腌。

為了防止消息丟失,RabbitMQ提供了消息響應(yīng)(acknowledgments)機制滞磺。消費者會通過一個ack(響應(yīng))升薯,告訴RabbitMQ已經(jīng)收到并處理了某條消息,然后RabbitMQ才會釋放并刪除這條消息击困。

如果消費者(consumer)掛掉了涎劈,沒有發(fā)送響應(yīng)广凸,RabbitMQ就會認為消息沒有被完全處理,然后重新發(fā)送給其他消費者(consumer)蛛枚。這樣谅海,即使工作者(workers)偶爾的掛掉,也不會丟失消息蹦浦。

消息是沒有超時這個概念的扭吁;當工作者與它斷開連的時候,RabbitMQ會重新發(fā)送消息盲镶。這樣在處理一個耗時非常長的消息任務(wù)的時候就不會出問題了侥袜。

消息響應(yīng)默認是開啟的。在之前的例子中使用了no_ack=True標識把它關(guān)閉溉贿。是時候移除這個標識了系馆,當工作者(worker)完成了任務(wù),就發(fā)送一個響應(yīng)顽照。

channel.BasicConsume(false, consumer);true){? ? BasicDeliverEventArgs)consumer.Queue.Dequeue();? ? var body = ea.Body;? ? Encoding.UTF8.GetString(body);? ? '.').Length - 1;? ? Thread.Sleep(dots * 1000);? ? <span , message);? ? <span );? ? channel.BasicAck(ea.DeliveryTag, false);}

現(xiàn)在,可以保證,即使正在處理消息的工作者被停掉,這些消息也不會丟失,所有沒有被應(yīng)答的消息會被重新發(fā)送給其他工作者.

一個很常見的錯誤就是忘掉了BasicAck這個方法,這個錯誤很常見,但是后果很嚴重. 當客戶端退出時,待處理的消息就會被重新分發(fā),但是RabitMQ會消耗越來越多的內(nèi)存,因為這些沒有被應(yīng)答的消息不能夠被釋放由蘑。調(diào)試這種case,可以使用rabbitmqct打印messages_unacknoledged字段代兵。

rabbitmqctl list_queues name messages_ready messages_unacknowledgedListing queues ...hello? ? 0? ? ? 0...done.

2.4 消息持久化

前面已經(jīng)搞定了即使消費者down掉尼酿,任務(wù)也不會丟失,但是植影,如果RabbitMQ Server停掉了裳擎,那么這些消息還是會丟失。

當RabbitMQ Server 關(guān)閉或者崩潰思币,那么里面存儲的隊列和消息默認是不會保存下來的鹿响。如果要讓RabbitMQ保存住消息,需要在兩個地方同時設(shè)置:需要保證隊列和消息都是持久化的谷饿。

首先惶我,要保證RabbitMQ不會丟失隊列,所以要做如下設(shè)置:

true;channel.QueueDeclare(null);

雖然在語法上是正確的博投,但是在目前階段是不正確的绸贡,因為我們之前已經(jīng)定義了一個非持久化的hello隊列。RabbitMQ不允許我們使用不同的參數(shù)重新定義一個已經(jīng)存在的同名隊列毅哗,如果這樣做就會報錯√拢現(xiàn)在,定義另外一個不同名稱的隊列:

true;channel.queueDeclare(null);

queueDeclare 這個改動需要在發(fā)送端和接收端同時設(shè)置虑绵。

現(xiàn)在保證了task_queue這個消息隊列即使在RabbitMQ Server重啟之后尿瞭,隊列也不會丟失。 然后需要保證消息也是持久化的翅睛, 這可以通過設(shè)置IBasicProperties.SetPersistent 為true來實現(xiàn):

var properties = channel.CreateBasicProperties();properties.SetPersistent(true);

需要注意的是声搁,將消息設(shè)置為持久化并不能完全保證消息不丟失红符。雖然他告訴RabbitMQ將消息保存到磁盤上劲腿,但是在RabbitMQ接收到消息和將其保存到磁盤上這之間仍然有一個小的時間窗口砸烦。 RabbitMQ 可能只是將消息保存到了緩存中季稳,并沒有將其寫入到磁盤上揭璃。持久化是不能夠一定保證的披蕉,但是對于一個簡單任務(wù)隊列來說已經(jīng)足夠榛臼。如果需要消息隊列持久化的強保證峻厚,可以使用publisher confirms

2.5 公平分發(fā)

你可能會注意到霞玄,消息的分發(fā)可能并沒有如我們想要的那樣公平分配骤铃。比如,對于兩個工作者坷剧。當奇數(shù)個消息的任務(wù)比較重惰爬,但是偶數(shù)個消息任務(wù)比較輕時,奇數(shù)個工作者始終處理忙碌狀態(tài)惫企,而偶數(shù)個工作者始終處理空閑狀態(tài)撕瞧。但是RabbitMQ并不知道這些,他仍然會平均依次的分發(fā)消息狞尔。

為了改變這一狀態(tài)丛版,我們可以使用basicQos方法,設(shè)置perfetchCount=1 偏序。這樣就告訴RabbitMQ 不要在同一時間給一個工作者發(fā)送多于1個的消息页畦,或者換句話說。在一個工作者還在處理消息研儒,并且沒有響應(yīng)消息之前豫缨,不要給他分發(fā)新的消息。相反端朵,將這條新的消息發(fā)送給下一個不那么忙碌的工作者好芭。

channel.BasicQos(0, 1, false);

2.6 完整實例

現(xiàn)在將所有這些放在一起:

發(fā)送端代碼如下:

string[] args){? ? ConnectionFactory();? ? factory.HostName = <span ;? ? factory.UserName = <span ;? ? factory.Password = <span ;? ? var connection = factory.CreateConnection())? ? {? ? ? ? var channel = connection.CreateModel())? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? true;? ? ? ? ? ? channel.QueueDeclare(null);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? string message = GetMessage(args);? ? ? ? ? ? var properties = channel.CreateBasicProperties();? ? ? ? ? ? properties.SetPersistent(true);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Encoding.UTF8.GetBytes(message);? ? ? ? ? ? channel.BasicPublish(<span , properties, body);? ? ? ? ? ? <span , message);? ? ? ? }? ? }? ? Console.ReadKey();}string[] args){? ? <span );}

接收端代碼如下:

string[] args){? ? ConnectionFactory();? ? factory.HostName = <span ;? ? factory.UserName = <span ;? ? factory.Password = <span ;? ? var connection = factory.CreateConnection())? ? {? ? ? ? var channel = connection.CreateModel())? ? ? ? {? ? ? ? ? ? true;? ? ? ? ? ? channel.QueueDeclare(null);? ? ? ? ? ? channel.BasicQos(0, 1, false);? ? ? ? ? ? QueueingBasicConsumer(channel);? ? ? ? ? ? channel.BasicConsume(false, consumer);? ? ? ? ? ? true)? ? ? ? ? ? {? ? ? ? ? ? ? ? BasicDeliverEventArgs)consumer.Queue.Dequeue();? ? ? ? ? ? ? ? var body = ea.Body;? ? ? ? ? ? ? ? Encoding.UTF8.GetString(body);? ? ? ? ? ? ? ? '.').Length - 1;? ? ? ? ? ? ? ? Thread.Sleep(dots * 1000);? ? ? ? ? ? ? ? <span , message);? ? ? ? ? ? ? ? <span );? ? ? ? ? ? ? ? channel.BasicAck(ea.DeliveryTag, false);? ? ? ? ? ? }? ? ? ? }? ? }}

三 管理界面

RabbitMQ還有一個管理界面,通過該界面可以查看RabbitMQ Server 當前的狀態(tài)冲呢,該界面是以插件形式提供的栓撞,并且在安裝RabbitMQ的時候已經(jīng)自帶了該插件。需要做的是在RabbitMQ控制臺界面中啟用該插件碗硬,命令如下:

rabbitmq-plugins enable rabbitmq_management

現(xiàn)在瓤湘,在瀏覽器中輸入 http://server-name:15672/ server-name換成機器地址或者域名,如果是本地的恩尾,直接用localhost(RabbitMQ 3.0之前版本端口號為55672)在輸入之后弛说,彈出登錄界面,使用我們之前創(chuàng)建的用戶登錄翰意。

在該界面上可以看到當前RabbitMQServer的所有狀態(tài)木人。

四 總結(jié)

本文簡單介紹了消息隊列的相關(guān)概念信柿,并介紹了RabbitMQ消息代理的基本原理以及在Windows 上如何安裝RabbitMQ和在.NET中如何使用RabbitMQ。消息隊列在構(gòu)建分布式系統(tǒng)和提高系統(tǒng)的可擴展性和響應(yīng)性方面有著很重要的作用醒第,希望本文對您了解消息隊列以及如何使用RabbitMQ有所幫助渔嚷。

五 參考文獻

http://www.infoq.com/cn/articles/message-based-distributed-architecture

http://www.rabbitmq.com/getstarted.html

http://www.codethinked.com/using-rabbitmq-with-c-and-net

http://www.infoq.com/cn/articles/AMQP-RabbitMQ

http://www.infoq.com/cn/articles/ebay-scalability-best-practices

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市稠曼,隨后出現(xiàn)的幾起案子形病,更是在濱河造成了極大的恐慌,老刑警劉巖霞幅,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漠吻,死亡現(xiàn)場離奇詭異,居然都是意外死亡司恳,警方通過查閱死者的電腦和手機途乃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扔傅,“玉大人耍共,你說我怎么就攤上這事×匀” “怎么了划提?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長邢享。 經(jīng)常有香客問我鹏往,道長,這世上最難降的妖魔是什么骇塘? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任伊履,我火速辦了婚禮,結(jié)果婚禮上款违,老公的妹妹穿的比我還像新娘唐瀑。我一直安慰自己,他們只是感情好插爹,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布哄辣。 她就那樣靜靜地躺著,像睡著了一般赠尾。 火紅的嫁衣襯著肌膚如雪力穗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天气嫁,我揣著相機與錄音当窗,去河邊找鬼。 笑死寸宵,一個胖子當著我的面吹牛崖面,可吹牛的內(nèi)容都是我干的元咙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼巫员,長吁一口氣:“原來是場噩夢啊……” “哼庶香!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起简识,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤赶掖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后财异,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡唱遭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年戳寸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拷泽。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡疫鹊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出司致,到底是詐尸還是另有隱情拆吆,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布脂矫,位于F島的核電站枣耀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏庭再。R本人自食惡果不足惜捞奕,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拄轻。 院中可真熱鬧颅围,春花似錦、人聲如沸恨搓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斧抱。三九已至常拓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辉浦,已是汗流浹背墩邀。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留盏浙,地道東北人眉睹。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓荔茬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親竹海。 傳聞我的和親對象是個殘疾皇子慕蔚,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)斋配,斷路器孔飒,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • % rabbitMQ learn% qijun% 19/01/2018 mq 的一些概念 mq: mq 是一個m...
    c7d122ec46c0閱讀 2,066評論 0 21
  • 利用RabbitMQ集群橫向擴展能力,均衡流量壓力艰争,讓消息集群的秒級服務(wù)能力達到百萬坏瞄,Google曾做過此類實驗;...
    有貨技術(shù)閱讀 3,454評論 0 1
  • 恩甩卓,會從考試成績出來了鸠匀,四分,就差四分逾柿,又沒過缀棍,第二次了你還要怎樣。這可能是我在知道成績后那天下午腦子里想最多的机错,...
    Jachinzhao閱讀 341評論 0 1
  • 毛小宇 自從有了你爬范,這個世界便多了一份牽掛。但是面對你頻繁的夜吵弱匪,玩具被你丟的滿房間都是青瀑,全身上下都是彩色筆的墨水...
    余瑤奶瓶閱讀 326評論 0 0