基於Masstransit實現Eventbus的功能

成天發表於2019-07-24

Masstransit 是一個非常優秀的基於訊息進行通訊的分散式應用程式框架,詳情參考官網

在介紹AA.ServiceBus開源地址:https://github.com/ChengLab/AAFrameWork  之前,先介紹下幾個概念.

分散式

分散式系統如何定義?這裡引用一下Distributed Systems Concepts and Design(Third Edition)中的一句話:"A distributed system is one in which components located at networked computers communicate and coordinate their actions only by passing messages"(分散式系統是指位於聯網計算機上的元件僅通過傳遞訊息來通訊和協調其操作的系統)。從這句話裡面我們可以看到幾個重點:
1、元件分佈在網路計算機上
2、元件之間僅僅通過訊息傳遞來通訊並協調行動
嚴格講,同一個分散式系統中的計算機在空間部署上是可以隨意分佈的,這些計算機可能被放在不同的機櫃上,也可能在不同的機房中,甚至分佈在不同的城市。

 中介軟體

中介軟體是介於作業系統和在其上執行的應用程式之間的軟體。中介軟體實質上充當隱藏轉換層,實現了分散式應用程式的通訊和資料管理。它有時被稱為管道,因為它將兩個應用程式連線在一起,使資料和資料庫可在“管道”間輕鬆傳遞。參考Azure

常見的中介軟體比如:遠端過程呼叫中介軟體,訊息中介軟體,資料庫訪問中間。 

訊息中介軟體

Message-oriented middleware (MOM) is software or hardware infrastructure supporting sending and receiving messages between distributed systems. 

面向訊息的中介軟體(MOM)是支援在分散式系統之間傳送和接收訊息的軟體或硬體基礎設施 

 

AA.ServiceBus 介紹

AA.ServiceBus 是基於MassTransit的訊息中介軟體,提供點對點和釋出訂閱的通訊方式。這兩個之間的區別:

  •   端點對端點通訊 該訊息僅處理一次 並且被一個消費者處理。

 例如命名模式 命令告訴服務做某事,推薦動詞-名詞順序的命名風格:如提交訂單命令(SubmitOrder)

  •  釋出訂閱通訊 可以被多個訂閱者進行消費處理。

例如事件驅動模式 事件意味著某事已經發生了,推薦以名詞-動詞(過去時態)順序的命名風格,表明發生了某事。示例訂單提交過了事件 OrderSubmitted

 目前實現訊息中介軟體有多種方式,參考微服務.NET:容器化應用架構指南 如圖

AA.ServiceBus 快速開始 

   例項我們建立兩個控制檯程式生產者、消費者分別命名ServiceBus.ProducersServiceBus.Consumers,然後在建立一個訊息契約類庫命名為ServiceBus.MsgContract ,分別被生產者和消費者引用。     

1.在訊息契約類庫中建立兩個訊息 分別是 提交訂單 SubmitOrder 和 訂單已提交OrderSubmitted程式碼如下

 public interface OrderSubmitted
    {
        long Id { get; set; }
        decimal OrderPrice { get; set; }
    }

   public interface SubmitOrder
    {
        long Id { get; set; }
        Decimal OrderPrice { get; set; }
    }

2.在生產者控制檯專案中安裝Install-Package AA.ServiceBus -Version 1.0.0,生產者主要對訊息的構造然後進行傳送或釋出;

public class Producer
    {
        public static void TestProducer()
        {
            //rabbitmq 配置
            string rabbitMqUri = "rabbitmq://localhost:5672";
            string rabbitMqUserName = "your";
            string rabbitMqPassword = "your";


            PulishEvent(rabbitMqUri, rabbitMqUserName, rabbitMqPassword);
            SendCommand(rabbitMqUri, rabbitMqUserName, rabbitMqPassword);
        }

        /// <summary>
        /// 釋出事件
        /// </summary>
        /// <param name="rabbitMqUri"></param>
        /// <param name="rabbitMqUserName"></param>
        /// <param name="rabbitMqPassword"></param>
        private static void PulishEvent(string rabbitMqUri, string rabbitMqUserName, string rabbitMqPassword)
        {
            IBusControl busControl = ServiceBusManager.Instance.UseRabbitMq(rabbitMqUri, rabbitMqUserName, rabbitMqPassword)
                         .BuildEventProducer();

            TaskUtil.Await(busControl.Publish<OrderSubmitted>(new
            {
                Id = 1010,
                OrderPrice = 1024
            }));
        }
        /// <summary>
        /// 傳送命令
        /// </summary>
        /// <param name="rabbitMqUri"></param>
        /// <param name="rabbitMqUserName"></param>
        /// <param name="rabbitMqPassword"></param>
        private static void SendCommand(string rabbitMqUri, string rabbitMqUserName, string rabbitMqPassword)
        {
            string queueName = "submitorder.queue";

            ISendEndpoint busControl = ServiceBusManager.Instance.UseRabbitMq(rabbitMqUri, rabbitMqUserName, rabbitMqPassword)
                         .BuildCommandProducer(queueName);

            TaskUtil.Await(busControl.Send<SubmitOrder>(new
            {
                Id = 1010,
                OrderPrice=1024
            }));
        }
    }

     

 3.在消費者控制檯專案中安裝Install-Package AA.ServiceBus -Version 1.0.0,生產者需要建立對應的消費者進行處理訊息,只需要繼承IConsumer介面即可

 

public class Consumer
    {
        public static void TestConsumer()
        {
            //rabbitmq 配置
            string rabbitMqUri = "rabbitmq://localhost:5672";
            string rabbitMqUserName = "your";
            string rabbitMqPassword = "your";
            string queueName = "submitorder.queue";

            var busControl = ServiceBusManager.Instance.UseRabbitMq(rabbitMqUri, rabbitMqUserName, rabbitMqPassword)
             .RegisterConsumer<SubmitOrderCommandConsumer>(queueName)//註冊提交訂單命令消費者
             .RegisterConsumer<OrderSubmittedEventConsumer>(null)   //註冊訂單已建立事件消費者
             .Build();
            busControl.Start();
        }
    }
    /// <summary>
    ///訂單已經提交了  事件消費者
    /// </summary>
    public class OrderSubmittedEventConsumer : IConsumer<OrderSubmitted>
    {
        public async Task Consume(ConsumeContext<OrderSubmitted> context)
        {
            var @event = context.Message;
            Console.WriteLine($"接收到訂單建立了事件訊息單價:{@event.OrderPrice}");
            //do somethings...
        }
    }

    /// <summary>
    /// 提交訂單 命令消費者
    /// </summary>
    public class SubmitOrderCommandConsumer : IConsumer<SubmitOrder>
    {
        public async Task Consume(ConsumeContext<SubmitOrder> context)
        {
            var command = context.Message;
            Console.WriteLine($"接收到了建立訂單命令訊息單價:{command.OrderPrice}");
            //do somethings...
        }
    }

執行消費者和生產者控制檯 輸出如下:

 

相關文章