Web服务/WebApi的负载均衡

限时下载:

示例代码(dp4-WebBalance.rar)

https://files-cdn.cnblogs.com/files/blogs/721296/dp4-WebBalance_cnblogs.rar?t=1663775011

【要点综述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”的解决方案+控制台工程。然后,我们做如下四步操作:

【第一步】:从NuGet添加引用DeveloperSharp包。并添加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:\Test2\YZZ.Client\log.txt" />    <add key="ConfigFile" value="D:\Test2\YZZ.Client\DeveloperSharp.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这个配置文件来实现?未完待续… 

总结

本文技术点思路梳理:

  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服务。

【附注】:下载示例均已成功运行通过。但有些辅助设置需要自己调整。