欢迎光临
我的个人博客网站

windows平台的分布式微服务解决方案(5)–Web服务/WebApi的负载均衡

本文技术点思路梳理:

  1. 创建Web服务组的通用基类“接口”。并在该“接口”上附加ServiceContract、OperationContract、WebInvoke三属性。
  2. 创建WCF服务并实现上述“接口”。并在Web.config中添加<services>与<endpointBehaviors>两项配置,让WCF服务兼具Web服务的特性。
  3. 把上述Web服务分别部署在网络上多个不同的地方,形成“Web服务组”。
  4. 通过DeveloperSharp.xml来配置“Web服务组”的负载均衡策略。
  5. 创建客户端,在其App.config/Web.config中添加链接DeveloperSharp.xml的appSettings节点。再在代码中创建基于DeveloperSharp.dll的“Web服务负载均衡调用”工具,并通过该工具调用远程的Web服务。

 

【要点综述1】:为了演示Web服务的负载均衡,本文会创建3个形式一致的web服务(或者说,创建1个web服务但分别拷贝部署在3个不同的地址),然后在客户端创建一个代理以“负载均衡”的算法形式远程调用这3个web服务。

【要点综述2】:为了实现“统一/透明”的调用形式连接“web服务端”与“客户端”两者,一个居中的“接口”类是必须创建的,且所有远程web服务需要继承此接口。

【要点综述3】:Web Api是一个经典的http服务提供形式,WCF也是一个经典的两端通信模式,本文还将会极巧妙的整合这两者,让一个服务一次编写同时具备Web Api与WCF两者的特性。

 

我们首先在Visual Studio中新建第一个名字叫“YZZ.Interface”的解决方案+类库工程,并在此工程中创建“IBase接口”与“Person实体类”,代码分别如下:

IBase接口:

using System.ServiceModel;//需要添加对System.ServiceModel.dll程序集的引用 using System.ServiceModel.Web;//需要添加对System.ServiceModel.Web.dll程序集的引用  namespace YZZ.Interface {     [ServiceContract]     public interface IBase     {         [OperationContract]         [WebInvoke(Method = "POST", UriTemplate = "/AccessRight", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]         Person AccessRight(int age);     } }

Person实体类:

namespace YZZ.Interface {     public class Person     {         public string name;         public int age;         public int right;     } }

如上代码所示,IBase接口中定义了一个通过年龄来做权限判断的AccessRight方法,并在该方法上附加了OperationContract与WebInvoke两个属性。OperationContract这个属性是用来给方法赋予WCF的特性,而WebInvoke这个属性则是给方法赋予了Web Api的特性。

编译该解决方案,获得YZZ.Interface.dll。

 

 

然后,我们再在Visual Studio中新建第二个名字叫“YZZ.Service”的解决方案+WCF服务应用程序工程,并在此工程中创建名为“MyBaseService.svc”的WCF服务文件,该文件的后台代码如下:

using YZZ.Interface;//需要添加前述IBase接口定义的YZZ.Interface.dll的引用  namespace YZZ.Service {     public class MyBaseService : IBase     {         public Person AccessRight(int age)         {             if (age > 27)                 return new Person { name = "管理员", age = age, right = 1 };             else                 return new Person { name = "学生/员工", age = age, right = 0 };         }     } }

如上代码所示,MyBaseService类实现了IBase接口中定义的AccessRight方法。

 

并且,此时我们还需要在此工程的Web.config中做如下两项配置,才能使得WCF与Web Api的特性在AccessRight方法身上完全见效。

配置一:在<system.serviceModel>节点下添加如下配置

    <!--用来对外发布WCF与WebAPI-->     <services>       <service name="YZZ.Service.MyBaseService">         <!-- 对应Web API的End Point -->         <endpoint address="webapi" binding="webHttpBinding" contract="YZZ.Interface.IBase" behaviorConfiguration="WebApiEndPointBehavior" />         <!-- 对应WCF的End Point -->         <endpoint address="" binding="basicHttpBinding" contract="YZZ.Interface.IBase" />       </service>       </services>

配置二:在<behaviors>节点下添加如下配置

      <!-- WCF Service转换为Web API后,使用的behavior -->       <endpointBehaviors>         <behavior name="WebApiEndPointBehavior">           <webHttp />         </behavior>       </endpointBehaviors>

如此一来,AccessRight方法就兼具了Web Api与WCF的双重特性。其Web Api(Web服务)的调用路径如下:

http://部署的服务器路径(ip+port)/MyBaseService.svc/webapi/AccessRight

 

 

为了演示Web服务的负载均衡的效果,现在我们把AccessRight方法的内容稍做修改成3个版本,分别编译YZZ.Service工程后部署在3个不同的地方(如何部署请参考其它资料,这是基础知识)。如下:

部署地址1:http://139.244.52.136:120/MyBaseService.svc

对应AccessRight代码1:

        public Person AccessRight(int age)         {             if (age > 27)                 return new Person { name = "管理员", age = age, right = 1 };             else                 return new Person { name = "学生/员工", age = age, right = 0 };         }

部署地址2:http://139.244.52.136:220/MyBaseService.svc

对应AccessRight代码2:

        public Person AccessRight(int age)         {             if (age > 27)                 return new Person { name = "管理员1", age = age, right = 1 };             else                 return new Person { name = "学生/员工1", age = age, right = 0 };         }

部署地址3:http://139.244.52.136:230/MyBaseService.svc

对应AccessRight代码3:

        public Person AccessRight(int age)         {             if (age > 27)                 return new Person { name = "管理员2", age = age, right = 1 };             else                 return new Person { name = "学生/员工2", age = age, right = 0 };         }

 

 

当“接口”与其对应的“3个Web服务”全部准备就绪,我们最后就来创建一个客户端以“负载均衡”的算法形式远程调用这3个web服务。

我们再次打开Visual Studio,新建第三个名字叫“YZZ.Client”的解决方案+控制台工程。然后,我们做如下四步操作:

【第一步】:为工程添加DeveloperSharp.dll核心组件引用。并添加YZZ.Interface.dll的引用。

【第二步】:创建一个名为DeveloperSharp.xml的配置文件,并在该文件中设置如上3个web服务的负载均衡策略。文件内容如下:

<?xml version="1.0" encoding="utf-8" ?> <DeveloperSharp>     <IServiceList>         <IService Id="YZZ.Interface.IBase">             <Service Id="A11" Enable="true" Weight="100" BindType="basicHttpBinding" Address="http://139.244.52.136:120/MyBaseService.svc"/>             <Service Id="A22" Enable="true" Weight="100" BindType="basicHttpBinding" Address="http://139.244.52.136:220/MyBaseService.svc"/>             <Service Id="A33" Enable="true" Weight="100" BindType="basicHttpBinding" Address="http://139.244.52.136:230/MyBaseService.svc"/>         </IService>     </IServiceList>    </DeveloperSharp>

对此xml配置文件说明如下:

(1)     每一个IService节点代表了一组Web服务,此节点的Id值(本文示例值是:YZZ.Interface.IBase)必须是这组Web服务的“基类接口”的完全限定名。

(2)     Service节点中的Weight属性代表了使用权重。本文示例的3个服务的Weight值分别是100、100、100,则这3个服务的负载均衡使用分配比例将会是1:1:1。若把这三个值分别设置为100、50、50,则这3个服务的使用分配比例将会变为2:1:1。设置成你想要的比例吧。

(3)     Service节点中的Enable属性代表了是否可用。true代表可用,false代表不可用。

 

【第三步】:在工程配置文件App.config(或Web.config)中添加appSettings节点,节点内容如下:

  <appSettings>     <add key="DatabaseType" value="" />     <add key="ConnectionString" value="" />     <add key="ErrorPage" value="" />     <add key="ErrorLog" value="D:Test2YZZ.Clientlog.txt" />     <add key="ConfigFile" value="D:Test2YZZ.ClientDeveloperSharp.xml" />   </appSettings>

其中,ConfigFile的设置是为了链接前述的DeveloperSharp.xml这个配置文件。ErrorLog则是设置一个错误日志文件。它们均需要设置为文件的“绝对路径”(此处使用“绝对路径”而不是“相对路径”,一是有利于安全性,二是有利于分布式部署)

【第四步】:在控制台应用类的代码中,添加创建“Web服务”负载均衡调用的工具IUtility.GetService<T>(),并通过该工具调用远程的Web服务,注意:核心代码就一行而已!!此示例连续3次调用Web服务,看会显示什么结果。如下:

    class Program     {         static void Main(string[] args)         {             YZZ.Interface.Person p;             DeveloperSharp.Framework.CoreUtility.IUtility IU = new DeveloperSharp.Framework.CoreUtility.Utility();//创建“Web服务”负载均衡调用的工具              //第一次调用远程Web服务             p = IU.GetService<YZZ.Interface.IBase>().AccessRight(20);             Console.WriteLine(p.name);              //第二次调用远程Web服务             p = IU.GetService<YZZ.Interface.IBase>().AccessRight(20);             Console.WriteLine(p.name);              //第三次调用远程Web服务             p = IU.GetService<YZZ.Interface.IBase>().AccessRight(20);             Console.WriteLine(p.name);              Console.ReadLine();         }     }

从以上示例代码我们可以清晰的得知:IUtility.GetService<T>()就是实现负载均衡的关键所在。泛型T需要设置为被调用“Web服务组”的“基类接口”,而IUtility.GetService<T>()方法则会每次根据配置的负载均衡策略创建对应的远程Web服务代理。

 

YZZ.Client控制台工程输出显示结果如下:

学生/员工

学生/员工1

学生/员工2

 

最后提示一点:若要把一组Web服务的负载均衡应用改为单Web服务应用,只需要把DeveloperSharp.xml配置文件中IService节点下的Service节点数量设置为一个即可实现。

 

后记:读完本文,你有没有发现,“微服务”中常用的注册、发现、服务降级、等功能,往往可通过修改DeveloperSharp.xml这个配置文件来实现?未完待续…

【本文采用.NET/C#语言撰写,如需其它语言版本,请联系作者索取。】

 

相关下载:

Web服务的负载均衡-示例代码(dp4-WebBalance.rar)

Web服务的负载均衡-示例代码(dp4-WebBalance.rar)

赞(0) 打赏
未经允许不得转载:张拓的天空 » windows平台的分布式微服务解决方案(5)–Web服务/WebApi的负载均衡
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

专业的IT技术经验分享 更专业 更方便

联系我们本站主机

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏