隨筆 - 41  文章 - 7  trackbacks - 0
          <2016年7月>
          262728293012
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          在這一章中,我們將涵蓋:
          1. 多線程和隊列
          2. 系統調整
          3. 改善帶寬
          4. 使用不同分發工具
          介紹
          這里沒有標準的RabbitMQ調優指南,因為不同應用程序會采用不同方式優化.
          通常情況下,應用程序需要在客戶端進行優化:
          1. 處理器密集型應用程序可以通過為每個處理器內核運行一個線程來進行優化
          2. I/O密集型應用程序可以通過在單核上運行多個線程來隱藏隱式延遲
          在兩種情況下,消息傳遞是完美的結合.為了優化網絡傳輸速率,AMQP標準規定消息按束(bunches)進行傳輸,然后再由客戶端一個一個地消費(參考第1章,使用AMQP).
          RabbitMQ 允許多線程應用程序高效地消費消息;這部分內容將在多線程和隊列食譜中涉及.

          另一個常見的用例是當RabbitMQ在分布式應用程序服務大量客戶的情況.在這種情況下,更為現實的瓶頸是broker而不是客戶端應用程序。在這種情況下,重要的是,我們的經紀人有一個特點,即:可擴展性。
          當客戶數量超過當前的最大容量閥值時,可在集群在增加一個或多個節點來分散負載,并提高總吞吐量。
          那為什么要到那時才來優化呢?其主要原因是減少硬件、電力、冷卻或云計算資源的成本。

          在章節中,我們將討論RabbitMQ的性能,同時也會展
          示一些技巧來提高客戶端的性能,并最終修改broker參數.
          多線程和隊列
          使用多線程也改善應用程序的性能.在本食譜中,我們將展示如何使用連接、通道、多線程.在這個例子中,我們使用的是Java,但一般來說,在目前多數技術中,使用多線程來提高性能是一種很好的實踐。
          你可在這里找到源碼:Chapter08/Recipe01.
          準備
          你需要Java 1.7+和Apache maven.
          如何做
          在這個例子中,我們繼承了ReliableClient Java 類 (參考第7章,開發高可用應用程序) 創建了一個producer,一個consumer. 讓我們看下面的詳細步驟:
          1. 創建一個maven project,并增加RabbitMQ client 依賴.
          2. 創建一個繼承ReliableClient的producer.
          3. 創建一個繼承ReliableClient的consumer.
          4. 使用下面的方法,為consumer和producer類創建一個ExecutorService Java類:
          ExecutorService exService =Executors.newFixedThreadPool(threadNumber);

          5. 以線程數目創建Runnable任務.producer如下:
          for (int i = 0; i<threadNumber; i++) {
          exService.execute(new Runnable() {
          @Override
          public void run() {
          try {
          publishMessages();
          6.以線程數目創建Runnable任務.consumer如下 :
          for (int i = 0; i<threadNumber; i++) {
          exService.execute(new Runnable() {
          @Override
          public void run() {
          final Channel internalChannel;
          try {
          internalChannel = connection.createChannel();
          @Override
          public void handleDelivery(String consumerTag,Envelope envelope, BasicProperties properties,byte[] body) throws IOException {..}

          如何工作
          ReliableClient 類創建了一個名為perf_queue_08/01的隊列, 它將綁定到一個producer和一個consumer. producer 和 consumer 都會打開一個連接,并會基于每個線程創建一個通道。
          通道可以在多個線程之間共享,但為了避免同步次數和一些鎖的問題,盡量對每個線程單獨創建一個通道。

          TIP
          通道并不總是線程安全的.這依賴于實現,例如,在使用 .NET client API時,在使用其方法前,你應該該對IModel加鎖.閱讀https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v3.1.5/rabbitmqdotnet-client-3.1.5-user-guide.pdf中的IModel should not be shared between threads章節.

          要開始多線程(步驟3),我們使用了Java ExecutorService 類的Executors.newFixedThreadPool(..).通過這種方式,你可以控制你的線程數目.
          TIP
          你可在 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html找到更多關于ExecutorService類和Java線程池的信息.


          在這個例子中,你可以選擇消息大小,運行時間,以及消費的消息數目.你可以使用下面的命令來創建rmqThreadTest.jar 文件:
          mvn clean compile assembly:single
          現在,你可以使用下面的命令來測試producer:
          java -cp rmqThreadTest.jar rmqexample.ProducerMain 4 10000 128
          第1個參數是線程數目;第二個參數是以毫秒為單位的運行時間;最后一個是以byte為單位的緩沖區大小.
          你可以使用下面的命令來測試consumer:
          java -cp rmqThreadTest.jar rmqexample.ConsumerMain 4
          參數是線程的數目.你可以結合producer和consumer參數來測試應用程序,并在你的環境中來找到更好的性能.打開web管理控制臺來檢查實際速率,如下面截圖所示:

          更多
          當隊列為空時,隊列比較快,在設計應用程序時,應該盡可能地讓隊列保持空的狀態在你的應用程序需要處理負載尖峰時,隊列容量會很方便。
          通過使用隊列,消息最終會被緩存并在不丟失任何信息的情況下地被處理.
          如果消費者的速度慢于生產者,那么你必須更加快速地消費消息,如:你可以嘗試添加更多的線程或消費者來加速消息的消費.

          TIP
          從3.2.0版本開始, RabbitMQ支持隊列聯合(http://www.rabbitmq.com/blog/2013/10/23/federated-queuesin-3-2-0/), 它可以在沒有集群的情況下, 均衡多個broker上的消息負載無論如何,如果你有一個以前版本的RabbitMQ,你必須將你的隊列手動地分配更多的broker。

          生產者和消費者線程的數量嚴格依賴于您的應用程序和部署環境。注意不要打開太多的線程,因為這可能會有相反的效果。
          系統調優
          在這個食譜中,我們會展示從RabbitMQ獲得最大性能的一些有用步驟。我們將涵蓋以下主題:
          1. vm_memory_high_watermark 配置 (http://www.rabbitmq.com/memory.html)
          2. Erlang High Performance Erlang (HiPE) (http://erlang.org/doc/apps/hipe/)
          vm_memory_high_watermark配置用于設置消息被消耗或緩存到磁盤前,所占用的最大系統內存百分比.在達到極限前,默認情況下,在vm_memory_high_watermark設置的百分之五十時,(或適當設置vm_memory_high_watermark_paging_ratio參數,默認情況下設置為0.5),RabbitMQ會開始將消息從內存移動到磁盤分頁空間上。
          如果沒有這個分頁機制,或者消費者趕不上生產者的步伐,這將導致達到極限,然后RabbitMQ將阻塞生產者。
          在某些情況下,加大這些參數是可能的,這樣可以避免消息過早地轉移到到磁盤上。在這個食譜中,我們將看到如何結合HIPE做。這里包含有兩個不同的方面,但完成他們所需要的步驟是非常相似的。
          你可以使用Chapter08/Recipe02目錄下的代碼.
          準備
          要嘗試本食譜,你必須從RabbitMQ開始,并安裝管理插件.接著,你還需要java 1.7+和Apache maven.
          如何做
          為了從RabbitMQ中獲取最大性能,你可以執行下面的步驟:
          1. 配置watermark:
          rabbitmqctl set_vm_memory_high_watermark 0.6
          或者直接在rabbitmq.config文件配置:
          [{rabbit, [{vm_memory_high_watermark, 0.6}]}].
          2. 修改Linux ulimit 參數,修改/etc/default/rabbitmqserver文件.然后,你可以使用HiPE來改善RabbitMQ自身.
          3. 從http://www.erlang.org/download.html來安裝最新版本的Erlang.
          4. 在你的系統中安裝HiPE.
          5. 檢查HiPE是否已正確激活;如果沒有,你需要從源碼來安裝Erlang,并將其激活.
          6. 在RabbitMQ 配置文件中激活Erlang HiPE. 創建rabbitmq.config文件并用下面的選項激活,或者現有的配置文件中添加下面的配置:
          [
          {rabbit, [{hipe_compile, true}]}
          ].
          7. 重啟RabbitMQ.
          8. 檢查RabbitMQ日志文件,確保沒有HiPE沒有激活的警告:
          =WARNING REPORT==== 6-Oct-2013::00:38:23 ===
          Not HiPE compiling: HiPE not found in this Erlang installation.

          如何工作
          watermark是RabbitMQ可使用的最大內存,默認情況下,其值為0.4,即它可使用安裝物理內存的40%.當內存達到watermark時,broker會停止接受新的連接和消息.watermark 值可以是近似的.
          在某些情況下,它可以不是默認的百分之40。無論如何,當服務器有大量的內存,你可以增加值,例如,只是為了容忍尖峰,可將增加到百分之60。
          與rabbitmqctl變化是暫時的相比,當你修改rabbitmq.config文件,該選項將設置為永久生效。
          默認情況下ulimit參數為1024。增加此值,可增加文件的數量和可用的RabbitMQ socket.
          TIP
          太高的值可能會對系統造成負面影響。在https://wiki.debian.org/limits可了解關于ulimit參數的說明。
          目前來說,Erlang HiPE是實驗性質的.如果它能工作,我們可以使用它,但如果系統不穩定,你需要禁用它.
          然而,對于RabbitMQ服務器來說,如果CPU是瓶頸的話,使用它,你可以獲得百分之40的CPU使用上的改進。 例如,在下面的截圖中,
          你可以看到在一個生產者和消費者的標準配置在本地broker的行為:

          在這個例子中,我們在本地同時運行producer和consumer, 300秒發送了32字節消息, 并讓消費者實時消費所有消息.
          當 HiPE激活后,如下面的截圖所示, 同樣的測試將表現得更好:

          在RabbitMQ配置文件中激活HiPE前,你可以通過調用下面的erl命令進行檢查:
          # erl
          Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:2:2] [asyncthreads:0] [hipe] [kernel-poll:false]
          EshellV5.9.3.1 (abort with ^G)
          1>
          這里HiPE是存在的,在啟動時,你可以看到[hipe]選項.

          TIP
          在 Debian wheeze 系統中,當從Erlang網站下載了最新Erlang版本時,你可以通過下面的命令來安裝HiPE模塊:
          apt-get install erlang-base-hipe 
          其它的發行包也有相似的可用包.

          否則,你需要使用外部包或從 http://www.erlang.org/download.html下載Erlang源碼包來安裝,同時在配置時,需要記得指定 --enable-hipe 選項.
          一旦RabbitMQ已經配置好了(步驟6),你將注意到服務器的重啟會花費較長時間,一般需要數分鐘.
          TIP
          在大部分Linux的發行版中,默認的RabbitMQ配置位于/etc/rabbitmq/rabbitmq.config.

          此時,RabbitMQ broker是HiPE激活的. 
          最苛刻的部分不被解釋了,但在啟動時編譯成本地機器代碼.
          你可以檢查日志文件,確保你不會看到下面的消息:
          =WARNING REPORT==== 6-Oct-2013::00:38:23 ===
          Not HiPE compiling: HiPE not found in this Erlang installation.


          TIP
          默認情況下,在Linux RabbitMQ上, 日志文件存放在/var/log/rabbitmq. 在12章節,管理RabbitMQ 錯誤條件中可找到更多信息.
          更多
          因為HIPE是實驗性的,我們不鼓勵從一開始就使用考慮到通常需要的優化,來解決應用程序的優化和可擴展性.
          然而,通過啟用它,您可以減少服務器的使用率和功耗,因此這是一個可以在優化您的架構時考慮的選項。

          改善帶寬
          使用noAck標志以及管理prefetch參數是另一種用來提高性能和帶寬的客戶端方式,它兩者都由消費者來使用的.
          在這個例子中,我們將使用這些參數來創建一個producer 和一個consumer. 你可在Chapter08/Recipe03找到源碼.
          準備
          你需要Java 1.7+和Apache maven.
          如何做
          我們將跳過produce代碼,因為它與多線程和隊列食譜中是一樣的. 我們仍然使用ReliableClient類來作基礎類. 我們可通過執行下面的步驟來查看consumer:
          1. 創建一個maven project,并添加RabbitMQ client依賴.
          2. 創建一個 consumer 主類,它可讀取args[]來管理consumer,其四個參數如下:
          threadNumber = Integer.valueOf(args[0]);
          prefetchcount = Integer.valueOf(args[1]);
          autoAck = (Integer.valueOf(args[2]) != 0);
          print_thread_consumer= (Integer.valueOf(args[3]) != 0);
          3. 創建一個繼承ReliableClient類的consumer,然后設置prefetch、noAck參數:
          internalChannel.basicQos(prefetch_count);
          internalChannel.basicConsume(Constants.queue, autoAck..

          如何工作
          如果設置了noAck選項時, 預提取大小(prefetch-size)將被忽略, 因此我們將本食譜分成兩部分講解:
          1. Prefetch
          2. noAck
          其目標是理解如何管理客戶端參數來改善性能和帶寬.
          Prefetch
          要設置prefetch,使用basicQos(prefetch_count) (步驟3).
          在第1章節使用AMQP,分發消息給多個消費者中,我們已經了解了channel QoS參數, 在那里,為了正解地負載均衡消息,消息是一個接一個地應答的.
          預取數是未確認消息的最大數目:較大的值會讓客戶提前預取的許多消息,而不用等待正在被處理消息的應答.
          正如本章開頭所說的,優化時,沒有一個通用的規則。
          事實上,提高預取數可能會適得其反,當每個消息的處理時間很重要時,我們需要分配和平衡處理。
          首先,Maven將使用下面的命令編譯:
          mvn clean compile assembly:single
          然后, maven會創建rmqAckTest.jar包.
          現在你可以嘗試這個例子,通過修改參數來查看消息速率的改變.我們在MacBook pro Dual Core, 4 GB RAM機器上使用下面的參數來測試:
          1.對于producer, 我們可以運行下面的命令:
          java -cp rmqAckTest.jar rmqexample.ProducerMain 1 100000 64000
          2.對于consumer,我們可以運行下面的兩個測試:
          java -cp rmqAckTest.jar rmqexample.ConsumerMain 2 50 0 0
          java -cp rmqAckTest.jar rmqexample.ConsumerMain 2 1 0 0
          producer使用 uses thread for 100 seconds and 64000 bytes as the message size.
          consumer 使用了 2個線程,在Test1中的預提取大小是50,Test2中是1autoAck設為了false, 并且不在控制臺中打印線程數目.
          兩種測試的結果如下:

          正如你所看到的,預提取大小不同,效果也不同,特別是有多個消費者綁定到同一個隊列上的時候.
          NoAck
          要設置noAck,使用basicConsume(Constants.queue, true). 當消息是數據流或者根本不關心手動應答時,此參數是很有用處的.
          TIP
          在Java API中, Channel.basicConsume 的act參數名稱作為Boolean類型的autoack,存在嚴重的誤導,實際上autoack=true表示我們會設置noAck選項.

          當設置了noAck時,你不能調用下面的方法:
          internalChannel.basicAck(envelope.getDeliveryTag(), false);
          嘗試將第三個參數(忽略了第二個)設置為1來測試  :
          java -cp rmqAckTest.jar rmqexample.ConsumerMain 1 1 1 0


          更多
          在優化消息傳遞操作時,可以通過應用方面的優化來獲得性能提升。這是可行的,無論是“小”和“大”的消息:
          1. 如果消息太小, 在發送前,你可以手動對它們進行打包,然后在接收端再進行解包
          2. 如果消息太大,在發送前,你可以嘗試壓縮消息,并在消費端進行解壓
          也可參考
          閱讀http://www.rabbitmq.com/blog/2012/04/17/rabbitmqperformance-measurements-part-1/ 和 http://www.rabbitmq.com/blog/2012/04/25/rabbitmq-performance-measurements-part-2/來理解如何單個參數的重要性.

          使用不同的分發工具
          當應用程序需要提高性能的時候,你需要選擇正確的分發工具. 在這個例子中,我們將展示發布消息時,鏡像隊列和非鏡像隊列之間的不同點.
          準備
          你需要Java 1.7+和Apache Maven.
          如何做
          你可以使用改善帶寬食譜中的源碼,并創建一個包含兩個節點的RabbitMQ集群.

          如何工作
          使用HA鏡像隊列的集群相比單個broker較慢。鏡像服務器的數目越高,應用程序就越慢,因為只有當消息全部存在鏡像節點之后,生產者才能發送更多的消息。

          TIP
          這并不像它看起來的那樣糟糕。一方面,對集群節點是并行執行的,所以開銷不會隨著節點的數量線性增長。另一方面,通常情況下,復制最多限制為兩到三份,這部分內容已在第7章,開發高可用應用程序中看到過了.

          我們使用下面的環境來執行測試:
          https://www.digitalocean.com/為云
          兩臺Debian機器為RabbitMQ集群,如下所示:

          一個Debian機具有相同特征的java客戶端測試如下:
          Test 1: 使用下面的配置創建一個鏡像(正如在第7章,開發高可用應用程序看到的),截圖如下:

          因此,集群會使用perf_ prefix來反射所有隊列.
          producer將使用下面的命令運行:
          java -cp rmqAckTest.jar rmqexample.ProducerMain 1 100000 640
          consumer使用下面的命令來運行:
          java -cp rmqAckTest.jar rmqexample.ConsumerMain 1 0 0 0
          clients通過perf_queue_08/03隊列來交換消息, 其性能如下所示:

          Test 2: 刪除HA策略并再次嘗試. 在這種情況下,其結果類似于下面的截圖:

          結論:通過使用小規模的消息,我們已經放大了差異。對于更大的信息,由差異不太明顯. 在 Test 2中, 我們已經觀察到比Test1每秒多了2000個消息,但同時也要看到,消息速率下降了,因為生產者快于消費者
          TIP
          作為通用規則,高可用性對性能有負面影響。所以,如果不具有強制性,最好把它關閉。

          在這個例子中,我們已經嘗試了最高性能,也看到鏡像隊列的影響.如果我們需要一定程度的復制,但對鏡像要求不嚴格,那么可以使用shovel插件,或者簡單地通過并行的方式將消息發布到兩個獨立的broker上.
          在這個例子中,消息不是持久化的,且沒有使用tx事務.

          TIP
          TX事務會扼殺性能,尤其是當你試圖提交每一條消息的時候,因為它會等待每條消息的磁盤刷新。
          更多
          由于在一個分布式應用程序中有大量的可變因素,因此在性能和可靠性之間找到正確的折衷是非常困難的。
          一個典型的錯誤是試圖優化每一個單個應用程序流丟失的可擴展性或最終高可用性的好處。
          本章介紹了極端的情況下,但我們已經看到,有改善的利潤率。

          也可參考
          性能是RabbitMQ郵件列表中非常熱門的話題。你可在http://rabbitmq.markmail.org/中找到很多有用的信息.

          posted on 2016-07-15 14:53 胡小軍 閱讀(9361) 評論(0)  編輯  收藏 所屬分類: RabbitMQ
          主站蜘蛛池模板: 根河市| 红桥区| 和顺县| 广德县| 天津市| 广州市| 安新县| 景宁| 威海市| 疏附县| 海阳市| 东莞市| 门源| 大化| 鄂尔多斯市| 景泰县| 开封市| 晋州市| 云林县| 宁海县| 古田县| 万载县| 铜陵市| 尚义县| 隆尧县| 申扎县| 扶风县| 玉门市| 崇阳县| 丰顺县| 武乡县| 宾阳县| 棋牌| 宜宾市| 奉新县| 平塘县| 昌乐县| 昆明市| 出国| SHOW| 阜南县|