三11、【WCF路由中間件】WCFHosting服務主機的路由器與負載均衡和實現思路

 回《【開源】EFW框架系列文章索引》       html

 EFW框架源代碼下載V1.3:http://pan.baidu.com/s/1c0dADO0算法

 EFW框架實例源代碼下載:http://pan.baidu.com/s/1eQCc69G安全

 

      前言:上一章《WCFHosting服務主機的利用WCF服務通信和實現思路 》中咱們詳細講解了WCF服務主機的通信功能,實現了客戶端與服務端的通信。光實現通信功能還不夠,中間件必定還要適合複雜的網絡環境,這樣增長了路由功能,還有系統性能問題那麼中間件必須分佈式部署,那麼負載均衡功能也必須有。服務器

 本文要點:網絡

1.路由器介紹及演示負載均衡

2.路由功能的實現框架

3.負載均衡的實現分佈式

4.WCF客戶端配置和中間件配置還有路由地址配置ide

5.總結性能

 

1.路由器介紹及演示

     WCF中間件的路由功能是在客戶端與服務端之間加入中介服務,用來轉發它們之間的消息。實現消息的轉發能夠修改WCF服務消息頭的內容,從新指定服務地址便可,那給消息頭指定的服務地址從哪來,須要給路由器配置服務端地址目錄,路由器與服務端確定不是一對一的,路由器能夠指定多個服務端,而路由器把客戶端鏈接指定給哪一個服務端這裏就有一個算法,算法的優劣就決定了中間件負載均衡的能力。

     下面演示了中間件的路由功能,把Out目錄中的程序複製6份,分別更名以下,3個客戶端,1個路有中間件,2個服務中間件,還要修改每一個程序的相關配置;這樣先啓動路由中間件Router和服務中間件WCFservser一、WCFServer2,而後分別啓動2個客戶端程序,路由中間件和服務中間件就會顯示客戶端的鏈接信息。3個客戶端會有2個分配到一個服務中間件,一個客戶端分配到另一個服務中間件,不會說3個客戶端都分配到1個服務中間件,這是由路由中間件的負載均衡算法決定的;

 

 

2.路由功能的實現

框架增長了一個路由服務對象Router,用它來攔截客戶端發送的消息,攔截方法ProcessMessage(Message requestMessage);

首先根據路由目錄結合負載均衡的算法取得服務地址endpointAddress,而後建立WCF通道並綁定新的服務地址,調用服務端的方法;

/// <summary>
        /// 截獲從Client端發送的消息轉發到目標終結點並得到返回值給Client端
        /// </summary>
        /// <param name="requestMessage"></param>
        /// <returns></returns>
        public Message ProcessMessage(Message requestMessage)
        {
            //Binding binding = null;
            EndpointAddress endpointAddress = null;
            GetServiceEndpoint(requestMessage, out endpointAddress);
            IDuplexRouterCallback callback = OperationContext.Current.GetCallbackChannel<IDuplexRouterCallback>();
            NetTcpBinding tbinding = new NetTcpBinding("netTcpExpenseService_ForSupplier");
            using (DuplexChannelFactory<IRouterService> factory = new DuplexChannelFactory<IRouterService>(new InstanceContext(null, new DuplexRouterCallback(callback)), tbinding, endpointAddress))
            {

                factory.Endpoint.Behaviors.Add(new MustUnderstandBehavior(false));
                IRouterService proxy = factory.CreateChannel();

                using (proxy as IDisposable)
                {
                    // 請求消息記錄
                    IClientChannel clientChannel = proxy as IClientChannel;
                    //Console.WriteLine(String.Format("Request received at {0}, to {1}\r\n\tAction: {2}", DateTime.Now, clientChannel.RemoteAddress.Uri.AbsoluteUri, requestMessage.Headers.Action));
                    if (Convert.ToInt32(HostSettingConfig.GetValue("debug")) == 1)
                        hostwcfMsg(DateTime.Now, String.Format("路由請求消息發送:  {0}", clientChannel.RemoteAddress.Uri.AbsoluteUri));
                    // 調用綁定的終結點的服務方法
                    Message responseMessage = proxy.ProcessMessage(requestMessage);

                    // 應答消息記錄
                    //Console.WriteLine(String.Format("Reply received at {0}\r\n\tAction: {1}", DateTime.Now, responseMessage.Headers.Action));
                    //Console.WriteLine();
                    //hostwcfMsg(DateTime.Now, String.Format("應答消息: {0}", responseMessage.Headers.Action));
                    return responseMessage;
                }
            }
        }
View Code

 

3.負載均衡的實現

       負載均衡實現代碼在Router對象中的GetServiceEndpoint方法中,定義了RegistrationList對象用來存儲客戶端列表,在消息頭中增長了兩個標識routerID和CMD,routerID用來識別客戶端,值是客戶端建立發送到路由中間件,每一個客戶端只有一個routerID;CMD用來客戶端發送給路由中間件的命令標識,這裏只用到了一個就是」Quit」就是卸載路由中間件中的RegistrationList客戶端列表;

       解決了識別客戶端的問題,那平均算法每一個客戶端分配到哪一個服務中間件就很簡單了,RoundRobinCount就記錄每一個服務中間件對應的客戶端個數,哪一個服務中間件數量少新的客戶端就分配給它;

private void GetServiceEndpoint(Message requestMessage,out EndpointAddress endpointAddress)
        {

            string ns = "http://www.3yxx.com/";
            string routerID = GetHeaderValue("routerID", ns);
            string cmd = GetHeaderValue("CMD", ns);
            string contractNamespace = requestMessage.Headers.Action.Substring(0, requestMessage.Headers.Action.LastIndexOf("/"));

           

            RegistrationInfo regInfo = null;

            if (Router.RoundRobinCount.ContainsKey(routerID))
            {
                int key = Router.RoundRobinCount[routerID];
                regInfo = Router.RegistrationList[key];
                if (cmd == "Quit")
                {
                    regInfo.ClientNum -= 1;
                }
            }
            else
            {
                //根據指定的協議名稱空間從註冊表容器中獲得註冊項列表
                var results = from item in Router.RegistrationList
                              where item.Value.ContractNamespace.Contains(contractNamespace)
                              orderby item.Value.ClientNum ascending
                              select item;
                if (results.Count<KeyValuePair<int, RegistrationInfo>>() > 0)
                {
                    var val = results.First<KeyValuePair<int, RegistrationInfo>>();
                    Router.RoundRobinCount.Add(routerID, val.Key);
                    val.Value.ClientNum += 1;
                    regInfo = val.Value;
                }
            }

            Uri addressUri = new Uri(regInfo.Address);

            //binding = CustomBindConfig.GetRouterBinding(addressUri.Scheme);
            endpointAddress = new EndpointAddress(regInfo.Address);
            //重設Message的目標終結點
            requestMessage.Headers.To = new Uri(regInfo.Address);

            hostwcfRouter(RegistrationList.Values.ToList());
        }
View Code

 

4.WCF客戶端配置和中間件配置還有路由地址配置

       若是部署的時候不使用中間件的路由功能,那客戶端配置服務地址直接指定服務端WCF地址就好了,而若是啓用路由功能,那客戶端就配置路由中間件的WCF地址,路由中間件再配置路由目錄,對應服務端;

       客戶端WCF配置和服務端WCF配置還有一個地方值得注意,就是netTcpBinding節點的配置;最好<security mode="None">配置爲取消服務器憑據認證,由於若是不配置爲None,當客戶端斷開鏈接後再鏈接的時候就會一些安全性驗證,致使鏈接報錯,因此對WCF安全性方面的配置沒有吃透的話仍是先這樣配置好;

1)客戶端App.Config配置

 

 

2)路由中間件App.Config配置和路由目錄RouterBill.xml配置

 

 

3)服務中間件App.Config配置

 

5.總結

       本章咱們詳細講解了EFW框架中的WCF中間件的路由功能和負載均衡的實現,代碼很簡單,但深刻理解卻沒那麼容易,我也只是略懂點皮毛,參考了網上資料把功能實現而已,而想要作成專業級別的中間件是有一個過程的,因此不僅是我,也須要有興趣的人一塊兒完善它;

 

路由實例程序下載:http://pan.baidu.com/s/1eQ8FscE

注意:實例中的配置文件中的IP地址192.168.1.3修改成你本機的IP地址;

 

資料參考:

構建 WCF 路由器,第 1 部分 :http://msdn.microsoft.com/zh-cn/magazine/cc500646.aspx

構建 WCF 路由器,第 2 部分:http://msdn.microsoft.com/zh-cn/magazine/cc546553.aspx

相關文章
相關標籤/搜索