好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

简易WCF负载均衡方案

简易WCF负载均衡方案

简易WCF负载均衡方案

最近跟高老师讨论nginx跟tomcat集群做负载均衡方案。感觉很有意思。想到自己项目中服务用的WCF技术,于是就想WCF如何做负载均衡,Google了一会,发现wcf4.0的路由服务好像可以实现。不过在研究路由服务期间,我有了个自己的方案,哈哈。

我要在客户端跟WCF服务中间部署一台WCF平衡服务器,用来分发请求,模拟nginx的工作。

WCF平衡服务器我同样用WCF来实现,所有服务接口全部通过平衡服务区暴露给客户端。对于客户端来说,只要跟正常调用服务一样,添加平衡器的远程服务引用。

实现: 1.平衡服务类库
 namespace  WcfSimpleBalance
{
     /// <summary> 
     /// 负载均衡基类 
     /// </summary> 
     /// <typeparam name="T"></typeparam> 
     public   class  WcfBalance<T>
    {
         private  ChannelFactory<T> _channelFactory;

         public  T BalanceProxy { get; set; }

         public  WcfBalance( string  serviceName)
        {
             string  endpoint = EndpointBalance.GetBalanceEndpoint(serviceName); //获取随机endpoint 
             this ._channelFactory =  new  ChannelFactory<T>(endpoint);
             this .BalanceProxy =  this ._channelFactory.CreateChannel();
        }
    }
}

其中泛型T为协定,这样就能动态构建wcf的通道了。

 namespace  WcfSimpleBalance
{
     internal   class  EndpointBalance
    {
         /// <summary> 
         /// 平衡节点配置 
         /// </summary> 
         private   static  List<WcfBalanceSection> _wcfBalanceCfg;
         static  EndpointBalance()
        {
            _wcfBalanceCfg = ConfigurationManager.GetSection( "wcfBalance" )  as  List<WcfBalanceSection>;
        }

         /// <summary> 
         /// 随机一个Endpoint 
         /// </summary> 
         /// <param name="serviceName"></param> 
         /// <returns></returns> 
         public   static   string  GetBalanceEndpoint( string  serviceName)
        {
            var serviceCfg = _wcfBalanceCfg.Single(s=>s.ServiceName==serviceName);
            var ran =  new  Random();
             int  i = ran.Next(0, serviceCfg.Endpoints.Count);
             string  endpoint = serviceCfg.Endpoints[i];
            Console.WriteLine(endpoint);
             return  endpoint;
        }
    }
} 
这个类提供一个静态方法可以根据服务名称从配置文件中配置的endpoint,并且从中随机一个。随机数的算法可能分布不是特别均匀,不知有什么好的办法。
 namespace  WcfSimpleBalance
{
     /// <summary> 
     /// 配置模型 
     /// </summary> 
     internal   class  WcfBalanceSection
    {
         public   string  ServiceName { get; set; }

         public  List< string > Endpoints { get; set; }
    }
     /// <summary> 
     /// 自定义配置处理 
     /// </summary> 
     public   class  WcfBalanceSectionHandler : IConfigurationSectionHandler
    {
         public   object  Create( object  parent,  object  configContext, XmlNode section)
        {
            var config =  new  List<WcfBalanceSection>();
             foreach  (XmlNode node  in  section.ChildNodes)
            {
                 if  (node.Name !=  "balanceService" )
                     throw   new  ConfigurationErrorsException( "不可识别的配置项" , node);
                var item =  new  WcfBalanceSection();
                 foreach  (XmlAttribute attr  in  node.Attributes)
                {
                     switch  (attr.Name)
                    {
                         case   "ServiceName" :
                            item.ServiceName = attr.Value;
                             break ;
                         case   "Endpoints" :
                            item.Endpoints = attr.Value.Split( ',' ).ToList();
                             break ;
                         default :
                             throw   new  ConfigurationErrorsException( "不可识别的配置属性" , attr);
                    }
                }
                config.Add(item);
            }
             return  config;
        }
    }
}
这2个是用来处理配置文件的。
2.普通的WCF服务 协定:
 namespace  WcfServiceContracts
{
     [ServiceContract(Name =  "CalculatorService" )]
     public   interface  IAdd
    {
         [OperationContract]
          int  Add( int  x,  int  y);
    }
}

一个简单的加法。

wcf服务实现:
 namespace  WcfService
{
     public   class  AddServices:IAdd
    {
         public   int  Add( int  x,  int  y)
        {
             return  x + y;
        }
    }
}
3.WCF平衡器实现

同样新建一个wcf服务类库,引用同样的协定,引用上面的平衡类库

 namespace  WcfServiceBalance
{
     public   class  AddServices : WcfBalance<IAdd>, IAdd
    {
         public  AddServices()
            :  base ( "AddServices" )
        {
        }

         public   int  Add( int  x,  int  y)
        {
             return  BalanceProxy.Add(x, y);
        }
    }
}

继承WcfBalance跟协定接口。构造函数调用基类的构造函数,传入服务名称。Add实现直接调用基类的方法。

模拟: 1.wcf服务器寄宿

WCF服务可以寄宿在多个方案下面,IIS,win服务,控制台。这里为了方便直接寄宿在控制台下。

新建2个控制台程序,一个寄宿普通的wcf服务。一个寄宿wcf平衡服务。代码不表,给出服务地址。

3个普通的服务。(把寄宿普通服务的控制台程序的bin目录复制3份,改3个端口就成了3个服务)

http://localhost:8081/Wcf  

http://localhost:8082/Wcf

http://localhost:8083/Wcf

平衡服务

http://localhost:8088/WcfBalance

配置文件

在平衡服务器的配置文件中定义所有后台服务器的endpoint,然后在自定义wcfBalance节点中配置,服务名对应的endpoint列表用逗号分隔。

 <?  xml   version  ="1.0"   encoding  ="utf-8"  ? > 
 <  configuration  > 
   <  configSections  > 
     <  section   name  ="wcfBalance"   type  ="WcfSimpleBalance.WcfBalanceSectionHandler, WcfSimpleBalance"   /> 
   </  configSections  > 
     <  wcfBalance  > 
        <  balanceService   ServiceName  ="AddServices"    Endpoints  ="AddService1,AddService2,AddService3"   /> 
     </  wcfBalance  > 
   <  system.serviceModel  > 
     <  bindings  > 
       <  basicHttpBinding  > 
         <  binding   name  ="BasicHttpBinding_CalculatorService"   /> 
       </  basicHttpBinding  > 
     </  bindings  > 
     <  client  > 
       <  endpoint   address  ="http://localhost:8081/Wcf"   binding  ="basicHttpBinding" 
           bindingConfiguration  ="BasicHttpBinding_CalculatorService" 
           contract  ="WcfServiceContracts.IAdd"   name  ="AddService1"   /> 
       <  endpoint   address  ="http://localhost:8082/Wcf"   binding  ="basicHttpBinding" 
           bindingConfiguration  ="BasicHttpBinding_CalculatorService" 
           contract  ="WcfServiceContracts.IAdd"   name  ="AddService2"   /> 
       <  endpoint   address  ="http://localhost:8083/Wcf"   binding  ="basicHttpBinding" 
           bindingConfiguration  ="BasicHttpBinding_CalculatorService" 
           contract  ="WcfServiceContracts.IAdd"   name  ="AddService3"   /> 
     </  client  > 
   </  system.serviceModel  > 
     <  startup  >  
         <  supportedRuntime   version  ="v4.0"   sku  =".NETFramework,Version=v4.5"   /> 
     </  startup  > 
 </  configuration  > 
2.客户端调用

添加平衡服务器引用,然后用代码调用。

启动30个线程去跑服务。

 namespace  WcfServiceClient
{
     class  Program
    {
         static   void  Main( string [] args)
        {
             for  ( int  i = 0; i < 30; i++)
            {
                var thread =  new  Thread( new  ThreadStart(CallAdd));
                thread.Start();
            }
            Console.Read();
        }

         private   static   void  CallAdd()
        {
             using  (var proxy =  new  CalculatorServiceClient())
            {
                proxy.Add(1,2);
            }
        }
    }
}

运行结果:

请求被分布到3个服务上面,不过貌似不太均匀,这个跟算法有关系。

通过以上我们实现了一个简单的wcf平衡服务器,这只是一个简单的方案,肯定有很多很多问题没有考虑到,希望大家指出讨论。

不过我想虽然实现了请求的分发,但是面对真正的高并发环境,平衡服务器会不会成为另外一个瓶颈。

BTW:求 苏州,上海地区有激情,有意义的技术类工作!!

Email:kklldog@gmail.com 
作者: Agile.Zhou(kklldog)  
出处: http://www.cnblogs.com/kklldog/  
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

 

标签:  WCF

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于简易WCF负载均衡方案的详细内容...

  阅读:41次