服务主机的路由器与负载均衡和实现思路

WCF中间件的路由功能是在客户端与服务端之间加入中介服务,用来转发它们之间的消息。实现消息的转发可以修改WCF服务消息头的内容,重新指定服务地址即可。

路由器介绍及演示

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

下面演示了中间件的路由功能,把Out目录中的程序复制6份,分别改名如下,3个客户端,1个路有中间件,2个服务中间件,还要修改每个程序的相关配置;这样先启动路由中间件Router和服务中间件WCFservser1、WCFServer2,然后分别启动2个客户端程序,路由中间件和服务中间件就会显示客户端的连接信息。3个客户端会有2个分配到一个服务中间件,一个客户端分配到另外一个服务中间件,不会说3个客户端都分配到1个服务中间件,这是由路由中间件的负载均衡算法决定的;

路由功能的实现

框架增加了一个路由服务对象Router,用它来拦截客户端发送的消息,拦截方法ProcessMessage(Message requestMessage);

首先根据路由目录结合负载均衡的算法取得服务地址endpointAddress,然后创建WCF通道并绑定新的服务地址,调用服务端的方法;

  1. ///<summary>
  2. ///截获从Client端发送的消息转发到目标终结点并获得返回值给Client端
  3. ///</summary>
  4. ///<paramname="requestMessage"></param>
  5. ///<returns></returns>
  6. publicMessageProcessMessage(MessagerequestMessage)
  7. {
  8. //Bindingbinding=null;
  9. EndpointAddressendpointAddress=null;
  10. GetServiceEndpoint(requestMessage,outendpointAddress);
  11. IDuplexRouterCallbackcallback=OperationContext.Current.GetCallbackChannel<IDuplexRouterCallback>();
  12. NetTcpBindingtbinding=newNetTcpBinding("netTcpExpenseService_ForSupplier");
  13. using(DuplexChannelFactory<IRouterService>factory=newDuplexChannelFactory<IRouterService>(newInstanceContext(null,newDuplexRouterCallback(callback)),tbinding,endpointAddress))
  14. {
  15. factory.Endpoint.Behaviors.Add(newMustUnderstandBehavior(false));
  16. IRouterServiceproxy=factory.CreateChannel();
  17. using(proxyasIDisposable)
  18. {
  19. //请求消息记录
  20. IClientChannelclientChannel=proxyasIClientChannel;
  21. //Console.WriteLine(String.Format("Requestreceivedat{0},to{1}\r\n\tAction:{2}",DateTime.Now,clientChannel.RemoteAddress.Uri.AbsoluteUri,requestMessage.Headers.Action));
  22. if(Convert.ToInt32(HostSettingConfig.GetValue("debug"))==1)
  23. hostwcfMsg(DateTime.Now,String.Format("路由请求消息发送:{0}",clientChannel.RemoteAddress.Uri.AbsoluteUri));
  24. //调用绑定的终结点的服务方法
  25. MessageresponseMessage=proxy.ProcessMessage(requestMessage);
  26. //应答消息记录
  27. //Console.WriteLine(String.Format("Replyreceivedat{0}\r\n\tAction:{1}",DateTime.Now,responseMessage.Headers.Action));
  28. //Console.WriteLine();
  29. //hostwcfMsg(DateTime.Now,String.Format("应答消息:{0}",responseMessage.Headers.Action));
  30. returnresponseMessage;
  31. }
  32. }
  33. }

负载均衡的实现

负载均衡实现代码在Router对象中的GetServiceEndpoint方法中,定义了RegistrationList对象用来存储客户端列表,在消息头中增加了两个标识routerID和CMD,routerID用来识别客户端,值是客户端创建发送到路由中间件,每个客户端只有一个routerID;CMD用来客户端发送给路由中间件的命令标识,这里只用到了一个就是”Quit”就是卸载路由中间件中的RegistrationList客户端列表;

解决了识别客户端的问题,那平均算法每个客户端分配到哪个服务中间件就很简单了,RoundRobinCount就记录每个服务中间件对应的客户端个数,哪个服务中间件数量少新的客户端就分配给它;

  1. privatevoidGetServiceEndpoint(MessagerequestMessage,outEndpointAddressendpointAddress)
  2. {
  3. stringns="http://www.3yxx.com/";
  4. stringrouterID=GetHeaderValue("routerID",ns);
  5. stringcmd=GetHeaderValue("CMD",ns);
  6. stringcontractNamespace=requestMessage.Headers.Action.Substring(0,requestMessage.Headers.Action.LastIndexOf("/"));
  7. RegistrationInforegInfo=null;
  8. if(Router.RoundRobinCount.ContainsKey(routerID))
  9. {
  10. intkey=Router.RoundRobinCount[routerID];
  11. regInfo=Router.RegistrationList[key];
  12. if(cmd=="Quit")
  13. {
  14. regInfo.ClientNum-=1;
  15. }
  16. }
  17. else
  18. {
  19. //根据指定的协议名称空间从注册表容器中得到注册项列表
  20. varresults=fromiteminRouter.RegistrationList
  21. whereitem.Value.ContractNamespace.Contains(contractNamespace)
  22. orderbyitem.Value.ClientNumascending
  23. selectitem;
  24. if(results.Count<KeyValuePair<int,RegistrationInfo>>()>0)
  25. {
  26. varval=results.First<KeyValuePair<int,RegistrationInfo>>();
  27. Router.RoundRobinCount.Add(routerID,val.Key);
  28. val.Value.ClientNum+=1;
  29. regInfo=val.Value;
  30. }
  31. }
  32. UriaddressUri=newUri(regInfo.Address);
  33. //binding=CustomBindConfig.GetRouterBinding(addressUri.Scheme);
  34. endpointAddress=newEndpointAddress(regInfo.Address);
  35. //重设Message的目标终结点
  36. requestMessage.Headers.To=newUri(regInfo.Address);
  37. hostwcfRouter(RegistrationList.Values.ToList());
  38. }

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

如果部署的时候不使用中间件的路由功能,那客户端配置服务地址直接指定服务端WCF地址就行了,而如果启用路由功能,那客户端就配置路由中间件的WCF地址,路由中间件再配置路由目录,对应服务端;

客户端WCF配置和服务端WCF配置还有一个地方值得注意,就是netTcpBinding节点的配置;最好配置为取消服务器凭据认证,因为如果不配置为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地址;(博客园

来源:互联网资源

0赞

好文章,需要你的鼓励

2015

02/25

17:55

分享

点赞

邮件订阅
白皮书