訊息智慧路由元件SmartRoute

smark發表於2015-08-17

         訊息傳遞在軟體開發過程中是一件很常見的事情,而在不同的場景所使用訊息傳遞方式也有所不同,在物件之間制定相關介面方法和物件結構,對於程式之間可能使用記憶體共享或一些通訊產品,在不同伺服器之的訊息通訊則使用一些通訊產品(MQ)或構建滿足自己的RPC通訊機制.不同場景技術人員都要掌握不同的技術方法來實現,由於應用技術和差異性容易導致開發成本和維護成本的上漲,為了解決這一系列的問題在這段時候思考後實現一種統一的訊息傳遞方式,而這種應用方式不管是物件間,程式或伺服器在應用上都不會任何差,在這裡稱這技術為訊息智慧路由(為了快速驗證想法,大概花了一週的業餘時間制定了一個可用的原型).

SmartRoute可實現場景

 

如何智慧?

         SmartRoute是依據訂閱者的ID來進行訊息傳送傳遞,類似於郵件地址一樣;只要在訂閱的時候制定相應的接收實現即可接收投遞到這一ID的訊息.然而這方式非常普通並沒有什麼所謂智慧高大上在這裡.其實SmartRoute的智慧優點在於技術人員完全不用去關心訂閱者所在的位置,不管是當前程式,其他應用程式還是其他伺服器,SmartRoute都可以自動地幫你投遞過去.最重要的是技術人員完全不用配置任何環境和安裝任何中間服務,只需要在程式中載入SmartRoute這系列的工作都可以自動完成(沒錯,即使你是跨伺服器投遞訊息也不需要做額外的配置和安裝中間伺服器);每個SmartRoute例項除承擔著接收和投遞工作的同時也承擔了訊息路由的角色;不同程式和不同伺服器執行的SmartRoute例項會自動組建叢集(而這個自動構建也不需要配置或安裝服務)

Hello應用

         一個元件的易用性才能體現它的價值,所以在設計SmartRoute的時候就遵循一個原則,在應用中儘量做到不需要配置即可用.以下通過通過簡單的Hello程式來描述一下元件設計的易用性.

l  HelloRequest

class Request : ISubscribeHandler
    {
        public Request()
        {
            Route.Subscribe("Ken", this);
        }

        public DateTime CreateTime
        {
            get;
            set;
        }

        public void Say(string name)
        {
            Hello hello = new Hello { Name ="hello "+ name };
            hello.SendTo(s => s.From("Ken"), "henry");
        }

        public ILogHandler Log
        {
            get;
            set;
        }

        public void Process(INode node, IMessage message)
        {
            Hello hello = message.GetBody<Hello>();
            Console.WriteLine("{0} Request  receive:{1}",DateTime.Now, hello.Name);
        }
    }

l  HelloReqponse

class Response : ISubscribeHandler
    {
        public Response()
        {
            Route.Subscribe("henry", this);
        }
        public DateTime CreateTime
        {
            get;
            set;
        }

        public ILogHandler Log
        {
            get;
            set;
        }

        public void Process(INode node, IMessage message)
        {
            Hello hello = message.GetBody<Hello>();
            Console.WriteLine("{0} response receive:{1}",DateTime.Now, hello.Name);
            hello.Name = "hello " + message.Sender;
            hello.SendTo(message.Sender);
        }
    }

Request和Response各自訂閱了資訊,通過實現ISubscribeHandler來接收投遞過來的訊息.可以通過執行以下程式碼來測試訂閱的有效性.

class Program
    {
        static Request request;
        static Response response;
        static void Main(string[] args)
        {
            request = new Request();
            response = new Response();
            while (true)
            {
                request.Say("henry");
                System.Threading.Thread.Sleep(3000);
            }
        }
    }

l  執行結果

擴充套件程式間通訊

         對於SmartRoute對現有的訂閱進行跨程式訪問則是一件非常簡單的事件,並不需要修改或配置任何程式碼即可完成.下面分別建兩個程式分別引用HelloRequest和HelloResponse

l  HelloRequestApp

class Program
    {
        static Request request;
        static void Main(string[] args)
        {
          
            request = new Request();
            while (true)
            {
                request.Say("henry");
                System.Threading.Thread.Sleep(3000);
            }
        }
    }

l  HelloResponseApp

class Program
    {
      
        static Response response;
        static void Main(string[] args)
        {
           
            response = new Response();
            System.Threading.Thread.Sleep(-1);
        }
    }

l  執行結果

伺服器間通訊

         SmartRoute在同一個區域網內會自動發現和組建路由,所以在不調整任何設計和程式碼的情況下,只需要把兩個應用部署在不同伺服器就可以進行資訊訂閱和傳送.

技術要點

l  通訊功能

除了本程式內訂閱和轉發不需要涉及到通訊外,程式和伺服器間都需要通訊服務.所以做這樣一個功能需要點通訊技術經驗,不過現在成熟的開發的通訊庫也有不少可以直接拿來用.

l  節點發現和握手

元件的靈活之處就是不需要任何配置就能實現互動,所以每個節點都具備發其他節點的能力;為了滿足這一需求需要使用UDP廣播技術,每個節點都會把自己的服務資訊廣播出去,當其他節點接收到這些資訊後就建立握手連線.

l  同步訂閱資訊

由於在設計的過程中強調沒有資料中心點,就是整個叢集裡的所有節點都是相互直連的.所以每個節點的訂閱資訊都會同步到不同節點上,這樣才能保證訊息投遞的有效性.為了保證訂閱的有效性同樣訂閱取的時候需要告訴其他節點變更情況.

l  制定訂閱規則

訂閱在接收訊息處理的情況是多樣性的,有可能是運算元據庫,HTTP或者網路轉發;所以需要給訂閱制定規劃,讓使用者可以實現不同的訂閱處理.

以下是一個簡單網路轉發訂閱

    public class TCPSubscribeHandler : ISubscribeHandler
    {
        public ILogHandler Log { get; set; }

        public IChannel Channel
        {
            get;
            set;
        }

        public void Process(INode node, IMessage message)
        {
            Channel.Server.Send(message,Channel);
        }

        public DateTime CreateTime
        {
            get;
            set;
        }
    }

下載DEMO

相關文章