RabbitMQ基礎入門篇

来源:https://www.cnblogs.com/wuchen1314/archive/2018/05/22/9072603.html
-Advertisement-
Play Games

下載安裝 "Erlang" "RabbitMQ" 啟動RabbitMQ管理平臺插件 DOS下進入到安裝目錄\sbin,執行以下命令 當出現以下結果時,重啟RabbitMQ服務 訪問 "http://localhost:15672" (賬號密碼:guest) 註意:以下為C 代碼,請引用NuGet包: ...


下載安裝

Erlang
RabbitMQ

啟動RabbitMQ管理平臺插件

DOS下進入到安裝目錄\sbin,執行以下命令

rabbitmq-plugins enable rabbitmq_management   

當出現以下結果時,重啟RabbitMQ服務

set 3 plugins.
Offline change; changes will take effect at broker restart.

訪問http://localhost:15672(賬號密碼:guest)

註意:以下為C#代碼,請引用NuGet包:RabbitMQ.Client

參考文章

RabbitMQ快速入門

名詞解析

P(Publisher):生產者
C(Consumer):消費者
Channel:通道
Queue:隊列
Exchange:信息交換機

簡單演示

信息發送端

static void Send()
{
    //1. 實例化連接工廠
    var factory = new ConnectionFactory() { HostName = "localhost" };
    //2. 建立連接
    using (var connection = factory.CreateConnection())
    {
        //3. 創建通道
        using (var channel = connection.CreateModel())
        {
            //4. 聲明隊列
            channel.QueueDeclare(queue: "rabbitmq",
                                 durable: false,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);

            //5. 構建位元組數據包
            var message = "Hello RabbitMQ!";
            var body = Encoding.UTF8.GetBytes(message);

            //6. 發送數據包
            channel.BasicPublish(exchange: "",
                                 routingKey: "rabbitmq",
                                 basicProperties: null,
                                 body: body);

            Console.WriteLine(" [x] Sent {0}", message);
        }
    }
}

信息接收端

static void Receive()
{
    //1. 實例化連接工廠
    var factory = new ConnectionFactory() { HostName = "localhost" };
    //2. 建立連接
    using (var connection = factory.CreateConnection())
    {
        //3. 創建通道
        using (var channel = connection.CreateModel())
        {
            //4. 聲明隊列
            channel.QueueDeclare(queue: "rabbitmq",
                                 durable: false,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);

            //5. 構造消費者實例
            var consumer = new EventingBasicConsumer(channel);

            //6. 綁定消息接收後的事件委托
            consumer.Received += (model, ea) =>
            {
                var message = Encoding.UTF8.GetString(ea.Body);
                Console.WriteLine(" [x] Received {0}", message);
            };
            //7. 啟動消費者
            channel.BasicConsume(queue: "rabbitmq",
                                 autoAck: true,
                                 consumer: consumer);

            Console.WriteLine(" Press [enter] to exit.");
            Console.ReadLine();

        }
    }
}

輪詢調度

P生產的多個任務進入到隊列中,多個C間可以並行處理任務。預設情況下,RabbitMQ把信息按順序發送給每一個C。平均每個C將獲得同等數量的信息。

信息確認

按照最簡單的演示來說,信息一旦發送到C中,則該信息就會從隊列中移除。一旦中間信息處理異常/失敗,C端程式退出等,都將會導致信息未處理完成,而此時隊列中已將信息移除了,那麼就會導致一系列的問題。我們可以在C端設置手動確認信息,從而解決上述問題的發生。
Receive代碼塊

//6. 綁定消息接收後的事件委托
consumer.Received += (model, ea) =>
{
    var message = Encoding.UTF8.GetString(ea.Body);
    Console.WriteLine(" [x] Received {0}", message);
    Thread.Sleep(5000);//模擬耗時
    Console.WriteLine(" [x] Done");

    // 發送信息確認信號(手動信息確認)
    channel.BasicAck(ea.DeliveryTag, false);
};
//7. 啟動消費者
/*
 autoAck參數屬性
    true:自動信息確認,當C端接收到信息後,自動發送ack信號,不管信息是否處理完畢
    false:關閉自動信息確認,通過調用BasicAck方法手動進行信息確認
 */
channel.BasicConsume(queue: "rabbitmq",
                     autoAck: false,
                     consumer: consumer);

信息持久化

當RabbitMQ退出或死機時會清空隊列和信息。通過將隊列和信息標記為持久的,來告知RabbitMQ將信息持久化。

Send代碼塊

//4. 聲明隊列
//durable設置為true,表示此隊列為持久的。
//註意:RabbitMQ不允許你使用不同的參數重新定義一個已經存在的隊列,所以你需要重啟服務/更改隊列名稱
channel.QueueDeclare(queue: "rabbitmq",
                     durable: true, //標記隊列持久
                     exclusive: false,
                     autoDelete: false,
                     arguments: null);
//設置IbasicProperties.SetPersistent屬性值為true來標記我們的消息持久化
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
 
//5. 構建位元組數據包
var message = "Hello RabbitMQ!";
var body = Encoding.UTF8.GetBytes(message);
 
//6. 發送數據包
channel.BasicPublish(exchange: "",
                     routingKey: "rabbitmq",
                     basicProperties: properties, //指定BasicProperties
                     body: body);

公平調度

上述演示中,如果隊列中存在多個信息,在開啟多個C的情況下,只有一個C忙個不停,另外的卻一直處於空閑狀態。通過調用BasicQos,告知RabbitMQ在某個C信息處理完畢,並且已經收到信息確認之後,才可以繼續發送信息到這個C。否則,將會把信息分發到另外空閑的C。

Receive代碼塊

//4. 聲明隊列
channel.QueueDeclare(queue: "rabbitmq",
                     durable: true,
                     exclusive: false,
                     autoDelete: false,
                     arguments: null);
////設置prefetchCount為1來告知RabbitMQ在未收到消費端的消息確認時,不再分發消息
channel.BasicQos(prefetchSize: 0,
                 prefetchCount: 1,
                 global: false);

發佈/訂閱

上述中的演示,P推送信息至隊列中,C從隊列中處理信息。但是如果需要將P推送的信息至每個訂閱的C中處理信息,那麼我們就可以使用Exchange。

fanout(將信息分發到exchange上綁定的所有隊列上)

Send代碼塊

//1. 實例化連接工廠
var factory = new ConnectionFactory() { HostName = "localhost" };
//2. 建立連接
using (var connection = factory.CreateConnection())
{
    //3. 創建通道
    using (var channel = connection.CreateModel())
    {
        //4. 聲明信息交換機
        channel.ExchangeDeclare(exchange: "fanoutDemo",
                                type: "fanout");
 
        //5. 構建位元組數據包
        var message = "Hello RabbitMQ!";
        var body = Encoding.UTF8.GetBytes(message);
         
        //6. 發佈到指定exchange,fanout類型的會忽視routingKey的值,所以無需填寫
        channel.BasicPublish(exchange: "fanoutDemo",
                             routingKey: "",
                             basicProperties: null,
                             body: body);
 
        Console.WriteLine(" [x] Sent {0}", message);
    }
}

Receive代碼塊

//1. 實例化連接工廠
var factory = new ConnectionFactory() { HostName = "localhost" };
//2. 建立連接
using (var connection = factory.CreateConnection())
{
    //3. 創建通道
    using (var channel = connection.CreateModel())
    {
        //4. 聲明信息交換機
        channel.ExchangeDeclare(exchange: "fanoutDemo",
                                type: "fanout");
        //生成隨機隊列名稱
        var queueName = channel.QueueDeclare().QueueName;
        //綁定隊列到指定fanout類型exchange
        channel.QueueBind(queue: queueName,
                          exchange: "fanoutDemo",
                          routingKey: "");
         
        //5. 構造消費者實例
        var consumer = new EventingBasicConsumer(channel);
 
        //6. 綁定消息接收後的事件委托
        consumer.Received += (model, ea) =>
        {
            var message = Encoding.UTF8.GetString(ea.Body);
            Console.WriteLine(" [x] Received {0}", message);
        };
 
        channel.BasicConsume(queue: queueName,
                             autoAck: true,
                             consumer: consumer);
 
        Console.WriteLine(" Press [enter] to exit.");
        Console.ReadLine();
 
    }
}

direct(C綁定的隊列名稱須和P發佈指定的路由名稱一致)

Send代碼塊

//4. 聲明信息交換機
channel.ExchangeDeclare(exchange: "directDemo",
                        type: "direct");

//5. 構建位元組數據包
var message = "Hello RabbitMQ!";
var body = Encoding.UTF8.GetBytes(message);

//6. 發佈到指定exchange
channel.BasicPublish(exchange: "directDemo",
                     routingKey: "a",
                     basicProperties: null,
                     body: body);

Receive代碼塊

//4. 聲明信息交換機
channel.ExchangeDeclare(exchange: "directDemo",
                        type: "direct");
//生成隨機隊列名稱
var queueName = channel.QueueDeclare().QueueName;
//綁定隊列到指定direct類型exchange
channel.QueueBind(queue: queueName,
                  exchange: "directDemo",
                  routingKey: "b");

topic(支持通配符的路由規則)

通配字元:

  • *:匹配一個單詞
  • #:匹配0個或多個單詞
  • .:僅作為分隔符

Send代碼塊

//4. 聲明信息交換機
channel.ExchangeDeclare(exchange: "topicDemo",
                        type: "topic");
 
//5. 構建位元組數據包
var message = "Hello RabbitMQ!";
var body = Encoding.UTF8.GetBytes(message);
 
//6. 發佈到指定exchange
channel.BasicPublish(exchange: "topicDemo",
                     routingKey: "admin.user.error", //模擬後臺用戶錯誤
                     basicProperties: null,
                     body: body);

Receive代碼塊

//4. 聲明信息交換機
channel.ExchangeDeclare(exchange: "topicDemo",
                        type: "topic");
//生成隨機隊列名稱
var queueName = channel.QueueDeclare().QueueName;
//綁定隊列到指定topic類型exchange
channel.QueueBind(queue: queueName,
                  exchange: "topicDemo",
                  routingKey: "admin.*.#"); //訂閱所有後臺異常錯誤

RPC(遠程過程調用)

  1. 進行遠程調用的客戶端需要指定接收遠程回調的隊列,並申明消費者監聽此隊列。
  2. 遠程調用的服務端除了要申明消費端接收遠程調用請求外,還要將結果發送到客戶端用來監聽的結果的隊列中去。

客戶端代碼塊

var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
    using (var channel = connection.CreateModel())
    {
        var correlationId = Guid.NewGuid().ToString();
        var replyQueue = channel.QueueDeclare().QueueName;
 
        var properties = channel.CreateBasicProperties();
        properties.ReplyTo = replyQueue;
        properties.CorrelationId = correlationId;
 
        string number = args.Length > 0 ? args[0] : "30";
        var body = Encoding.UTF8.GetBytes(number);
        //發佈消息
        channel.BasicPublish(exchange: "", routingKey: "rpc_queue", basicProperties: properties, body: body);
 
        Console.WriteLine($"[*] Request fib({number})");
 
        // //創建消費者用於消息回調
        var callbackConsumer = new EventingBasicConsumer(channel);
        channel.BasicConsume(queue: replyQueue, autoAck: true, consumer: callbackConsumer);
 
        callbackConsumer.Received += (model, ea) =>
        {
            if (ea.BasicProperties.CorrelationId == correlationId)
            {
                var responseMsg = $"Get Response: {Encoding.UTF8.GetString(ea.Body)}";
 
                Console.WriteLine($"[x]: {responseMsg}");
            }
        };
 
        Console.ReadLine();
 
    }
}

服務端代碼塊

static void Main(string[] args)
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using (var conection = factory.CreateConnection())
    {
        using (var channel = conection.CreateModel())
        {
            channel.QueueDeclare(queue: "rpc_queue", durable: false,
                exclusive: false, autoDelete: false, arguments: null);
 
            var consumer = new EventingBasicConsumer(channel);
            Console.WriteLine("[*] Waiting for message.");
 
            consumer.Received += (model, ea) =>
            {
                var message = Encoding.UTF8.GetString(ea.Body);
                int n = int.Parse(message);
                Console.WriteLine($"Receive request of Fib({n})");
                int result = Fib(n);
 
                var properties = ea.BasicProperties;
                var replyProerties = channel.CreateBasicProperties();
                replyProerties.CorrelationId = properties.CorrelationId;
 
                channel.BasicPublish(exchange: "", routingKey: properties.ReplyTo,
                    basicProperties: replyProerties, body: Encoding.UTF8.GetBytes(result.ToString()));
 
                channel.BasicAck(ea.DeliveryTag, false);
                Console.WriteLine($"Return result: Fib({n})= {result}");
 
            };
            channel.BasicConsume(queue: "rpc_queue", autoAck: false, consumer: consumer);
 
            Console.ReadLine();
        }
    }
 
}
 
private static int Fib(int n)
{
    if (n == 0 || n == 1)
    {
        return n;
    }
    return Fib(n - 1) + Fib(n - 2);
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一 新建一個Java項目 二 新建一個Web項目 三 新建一個Maven項目 四 web.xml常見版本 五 pom.xml純凈版 ...
  • 數據類型 整數 浮點數 字元串 布爾值 空值 變數 常量 整數 浮點數 字元串 布爾值 空值 數據類型 Python可以處理任意大小的整數,也包括負整數。 在Python中,有兩種除法,一種是/:10 / 3,結果為3.33333333333333333,/除法計算結果是浮點數,即使兩個整數恰好整除 ...
  • 1:is 是判斷類型,用於檢查對象是否與給定類型相容,不成功則不會拋出異常,如果相容則返回true,如果不相容則返回false。在進行類型轉換之前用 在上面的例子中進行兩次相容性檢查,一在判斷時P_obj is System.String,另一次在轉換(string)P_obj時。用as只需要 一次 ...
  • 母版頁是一個擴展名為.master的ASP.NET文件,主要是為了應用程式創建統一的用戶功能界面和樣式。 ContentPlaceHolder控制項只能在母版頁中使用,在平常的web頁面使用,會發生解析器錯誤。 內容頁中可以有多個Content伺服器控制項,但內容頁里的Content控制項的Content ...
  • 一、課程介紹 本次分享課程屬於《C#高級編程實戰技能開發寶典課程系列》中的第五部分,阿笨後續會計劃將實際項目中的一些比較實用的關於C#高級編程的技巧分享出來給大家進行學習,不斷的收集、整理和完善此系列課程! 本次分享課程適合人群如下: 1、想學習Grid++Report報表工具在C/S項目中的實戰演 ...
  • 今天我們來探索一下Singleton設計模式的實現及應用場景。 Singleton模式屬於Creational Type(創建型)設計模式的一種。該模式一般用於確保在應用中僅創建一個某類的instance,在應用中的各個地方對該類的實例對象的引用均指向同一instacne。 Singleton模式的 ...
  • 20180522更新內容 本次更新增加了excel導入導出示例,QuerySuite組件實現導出導出,用最少代碼,做最多的事,代碼就是如此簡單。 計劃修改內容 1、人臉登錄功能需要重構,目前功能不完善。 2、QuerySuite類重構,同時支持mysql,oracle 3、增加視頻處理功能。 4、分 ...
  • 背景: 個人電腦 安裝的 VS2015 Community 社區版。 一直用得挺好,都忘了要登錄。 直到近來,30天試用期過 —— VS彈窗:要登錄用戶名、密碼 才能繼續使用。 但是,輸入了無數次 郵箱,到下一步時,都彈出一個 白屏視窗 —— 死活沒法登錄成功。 登錄不成功,日子還得過。 尊重著作權 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...