简易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测试数据
作者: Agile.Zhou(kklldog)
出处: http://HdhCmsTestcnblogs测试数据/kklldog/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
标签: WCF
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息