回《【开源】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}\r\n\tAction: {2}", DateTime.Now, clientChannel.RemoteAddress.Uri.AbsoluteUri, requestMessage.Headers.Action));
if (Convert.ToInt32(HostSettingConfig.GetValue("debug")) == )
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;
}
}
}

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(, 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 -= ;
}
}
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>>() > )
{
var val = results.First<KeyValuePair<int, RegistrationInfo>>();
Router.RoundRobinCount.Add(routerID, val.Key);
val.Value.ClientNum += ;
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());
}

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

三十一、【WCF路由中间件】WCFHosting服务主机的路由器与负载均衡和实现思路的更多相关文章

  1. 三十、【C#.Net开发框架】WCFHosting服务主机的利用WCF服务通讯和实现思路

    回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...

  2. SpringCloud初体验:三、Feign 服务间调用(FeignClient)、负载均衡(Ribbon)、容错/降级处理(Hystrix)

    FeignOpenFeign Feign是一种声明式.模板化的HTTP客户端. 看了解释过后,可以理解为他是一种 客户端 配置实现的策略,它实现 服务间调用(FeignClient).负载均衡(Rib ...

  3. 微服务Kong(十)——负载均衡参考

    KONG为请求多个后端服务提供了多种负载均衡方案:一种是简单的基于DNS,另一种是更加动态的环形均衡器,他在不需要DNS服务器的情况下也允许服务注册. 一.基于DNS的负载均衡 当使用基于DNS的负载 ...

  4. Spring Cloud微服务开发笔记5——Ribbon负载均衡策略规则定制

    上一篇文章单独介绍了Ribbon框架的使用,及其如何实现客户端对服务访问的负载均衡,但只是单独从Ribbon框架实现,没有涉及spring cloud.本文着力介绍Ribbon的负载均衡机制,下一篇文 ...

  5. Java微服务(二):负载均衡、序列化、熔断

    本文接着上一篇写的<Java微服务(二):服务消费者与提供者搭建>,上一篇文章主要讲述了消费者与服务者的搭建与简单的实现.其中重点需要注意配置文件中的几个坑. 本章节介绍一些零散的内容:服 ...

  6. springCloud搭建微服务集群+Zuul服务器端负载均衡

    概述 最近研究了一下springCloud的微服务集群,主要用到了SpringCloud的服务发现和服务器端负载均衡,所有的项目都是用的springboot,可以和springCloud无缝对接. 技 ...

  7. 微服务通信之feign集成负载均衡

    前言 书接上文,feign接口是如何注册到容器想必已然清楚,现在我们着重关心一个问题,feign调用服务的时候是如何抉择的?上一篇主要是从读源码的角度入手,后续将会逐步从软件构架方面进行剖析. 一.R ...

  8. springboot10-springcloud-eureka 服务注册与发现,负载均衡客户端(ribbon,feign)调用

    创建5个项目: 1.服务注册中心 2.服务提供者1 3.服务提供者2(与服务提供者1的代码实现一样,这是是为了模拟负载均衡) 4.ribbon客户端项目 5.feign客户端项目 如图: 一.注册中心 ...

  9. 基于Dubbo框架构建分布式服务(集群容错&负载均衡)

    Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ...

随机推荐

  1. 不要过早退出循环 while(1){no break}

    我们在尝试新的事物的时候,总是会遇到各种各样的困难,不同的人会在碰壁不同的次数之后退出.用程序员喜欢的话来说就是,我们都在for循环,区别在于你是什么情况下break的.有的人退出阈值高,这是能坚持的 ...

  2. webView文本长按显示英文

    webView文本长按显示英文时,在info.plist文件中添加如下内容: <key>CFBundleLocalizations</key> <array> &l ...

  3. atitit...触发器机制 ltrigger mechanism sumup .的总结O8f

    atitit...触发器机制  ltrigger  mechanism sumup .的总结O8f 1. 触发器的类型 1 2. 实现原理 1 3. After触发器 Vs Instead Of触发器 ...

  4. atitit. 集合groupby 的实现(2)---自定义linq查询--java .net php

    atitit.  集合groupby 的实现(2)---自定义linq查询--java .net php 实现方式有如下 1. Linq的实现原理流程(ati总结) 1 2. groupby  与 事 ...

  5. atitit. access token是什么??微信平台公众号开发access_token and Web session保持状态机制

    atitit. access token是什么??微信平台公众号开发access_token and Web session保持状态机制 1. token机制and  session保持状态机制 1 ...

  6. Leetcode 190 Reverse Bits 位运算

    反转二进制 class Solution { public: uint32_t reverseBits(uint32_t n) { uint32_t ans = ; ; i<; ++i,n &g ...

  7. Which Clang Warning Is Generating This Message?

    Which Clang Warning Is Generating This Message? 根据前面页面制作的pdf:clangwarninglist.pdf 百度网盘:http://pan.ba ...

  8. 【CUDA学习】全局存储器

    全局存储器,即普通的显存,整个网格中的任意线程都能读写全局存储器的任意位置. 存取延时为400-600 clock cycles  非常容易成为性能瓶颈. 访问显存时,读取和存储必须对齐,宽度为4By ...

  9. MySQL执行计划中key_len详解

    (1).索引字段的附加信息:可以分为变长和定长数据类型讨论,当索引字段为定长数据类型,比如char,int,datetime,需要有是否为空的标记,这个标记需要占用1个字节:对于变长数据类型,比如:v ...

  10. 【转载】酷酷的CSS3三角形运用

    转载:http://www.cnblogs.com/keepfool/p/5616326.html 概述 在早期的前端Web设计开发年代,完成一些页面元素时,我们必须要有专业的PS美工爸爸,由PS美工 ...