zoukankan      html  css  js  c++  java
  • 三十一、【WCF路由中间件】WCFHosting服务主机的路由器与负载均衡和实现思路

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

     EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0

     EFW框架实例源代码下载:http://pan.baidu.com/s/1eQCc69G

     

          前言:上一章《WCFHosting服务主机的利用WCF服务通讯和实现思路 》中我们详细讲解了WCF服务主机的通讯功能,实现了客户端与服务端的通讯。光实现通讯功能还不够,中间件一定还要适合复杂的网络环境,这样增加了路由功能,还有系统性能问题那么中间件必须分布式部署,那么负载均衡功能也必须有。

     本文要点:

    1.路由器介绍及演示

    2.路由功能的实现

    3.负载均衡的实现

    4.WCF客户端配置和中间件配置还有路由地址配置

    5.总结

     

    1.路由器介绍及演示

         WCF中间件的路由功能是在客户端与服务端之间加入中介服务,用来转发它们之间的消息。实现消息的转发可以修改WCF服务消息头的内容,重新指定服务地址即可,那给消息头指定的服务地址从哪来,需要给路由器配置服务端地址目录,路由器与服务端肯定不是一对一的,路由器可以指定多个服务端,而路由器把客户端连接指定给哪个服务端这里就有一个算法,算法的优劣就决定了中间件负载均衡的能力。

         下面演示了中间件的路由功能,把Out目录中的程序复制6份,分别改名如下,3个客户端,1个路有中间件,2个服务中间件,还要修改每个程序的相关配置;这样先启动路由中间件Router和服务中间件WCFservser1、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}
    	Action: {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}
    	Action: {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

  • 相关阅读:
    [ Pytorch ] torch.squeeze() 和torch.unsqueeze()的用法
    莫烦
    毕业设计 Makefile 编写
    Manjaro搭建无密访问samba服务器
    GEC6818交叉开发环境搭建拟稿
    彻底删除windows残留启动引导
    Cmd Markdown 编辑阅读器
    Hi3519v101 SDK安装及升级
    Linux 修改SWAP分区后导致开机问题
    Linux 安装搭建 tftpd 服务器
  • 原文地址:https://www.cnblogs.com/kakake/p/4052467.html
Copyright © 2011-2022 走看看