《Windows Azure Platform 系列文章目录》
相对于Input Endpoint而言,Windows Azure还提供了Internal Endpoint的概念。如果说Input Endpoint就是Windows Azure负载均衡服务器的一个映射配置,使得Role Instance的内部地址可以被映射到Hosted Service URL上的话,Internal Endpoint就可以理解为在Hosted Service中部署的所有Role之间开放的内部端口。这些端口虽然不能通过Hosted Service URL访问,但是可以被其他的Role访问。并且由于Windows Azure数据中心内部的网络传输速度极快,所以可以通过Internal Endpoint和NET.TCP实现Role之间的高速通信。下面就基于刚才的例子来介绍如何通过Internal Endpoint调用另外一个Role中的WCF服务。
为了演示方便,我们将此前EchoService中服务器端添加日期的功能分离到另外一个WCF Service中,让现在的EchoService调用这个新的服务来获取当前的系统日期。在Windows Azure项目中加入一个新的Worker Role,并且添加一个新的Class Library项目来包含WCF契约。将这个新服务命名为TimeService。
客户端通过Hosted Service URL访问Echo Service的Input Endpoint,然后Echo Service通过Time Service的Internal Endpoint调用日期服务来获取日期,最后Echo Service将日期等信息附加返回给客户端。为了演示内部调用的结果,在Time Service的返回值中还可以附加执行此请求的Time Service所侦听的地址和Role Instance ID,WCF契约部分的代码如下所示。
[ServiceContract]
public interface ITimeService
{
[OperationContract]
Time GetTime();
}
[DataContract]
public class Time
{
[DataMember]
public DateTime Value {get;set;}
[DataMember]
public string IPendpoint {get;set;}
[DataMember]
public string RoleInstanceID {get;set;}
}
接下来改造服务端代码,使Echo Service通过内部端口调用Time Service,如下图。首先在Endpoint页面为Time Service添加一个Internal Endpoint,选择TCP类型。当用户选择了Internal Endpoint的时候便无法指定其对外端口号。而对于内部端口(Private Port)用户可以在这个界面指定某个或某几个端口,如果不指定那么Windows Azure平台会在Role启动的时候随即分配一个。而对于动态端口,开发人员在代码中可以通过RoleEnvironment类的相关方法得到具体的端口号。
接下来实现Time Service的具体逻辑。为了测试需要,在返回当前系统日期的同时,还将刚才设定的Internal Endpoint的地址以及Role Instance ID一并返回。
public class TimeService : ITimerService
{
public Time GetTime()
{
var date = DateTime.Now;
var endpoint=RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["TimeEndpoint"].IPEdpoint;
var instanceId=RoleEnvironment.CurrentRoleInstance.Id;
return new Time()
{
Value=date,
IPEndpoint=endpoint.ToString(),
RoleInstanceID=instanceId
};
}
}
然后再Worker Role中寄宿服务。由于现在是通过端口号不固定的Internal Endpoint发布,因此只能通过代码方式进行配置。
最后修改Echo Service的实现,调用Time Service来获取系统时间。同样由于Time Service的Internal Endpoint是动态的,并且Time Service也可能有多个Instance,所以在调用的时候需要通过RoleEnvironment类的InstanceEndpoints属性指定Internal Endpoint的名字来获取具体的地址,同时还需要随机分配链接的Tier Service Role Instance来实现一个小的负载均衡操作。代码如下
public string Echo(string content)
{
//retrive all endpoints belongs to the time service role
var endpoints= RoleEnvironment.Roles["TimeService.Service"].Instances
.Select(instance => instance.InstanceEndpoints["TimeEndpoint"])
.ToList();
//random select a time service instance to connect to simulate the load balance
var endpoint = endpoints[_rnd.Next(0,endpoints.Count)];
}
在代码中可以看到,程序通过RoleEnvironment的Roles属性获取其Time Service Role的信息,然后针对这个Role的所有Instance获取Internal Endpoint地址并保存在一个列表中。随后,随机得选择一个Instance的Endpoint作为这次调用的地址。
下面基于这个随机地址通过ChannelFactory得到代理类,进而调用Time Service,代码如下:
public string Echo(string content)
{
//retrive all endpoints belongs to the time service role
var endpoints = RoleEnvironment.Roles["TimeService.Service"].Instance
.Select(instance => instance.InstanceEndpoints["TimeEndpoint"]
.ToList();
//random select a time service instance to connect to simulate the load balance
var endpoint = endpoints[_rnd.Next(0,endpoints.Count)];
//create the channel factory and proxy to comunicate
var factory = new ChannelFactory<ITimeService>(new NetTcpBinding (SecurityMode.None));
var proxy = factory.CreateChannel(new EndpointAddress(string.Format(""net.tcp://{0}
/TimeService",endpoint.IPEndpoint)));
Time result = null;
using (proxy as IDisposable)
{
result = proxy.GetTime();
}
}
最后,将获得的时间连同附加信息返回给客户端。这样客户端得到的结果就可以显示这个Echo Service在执行的时候是通过哪个内部Endpoints访问哪个Instance的Time Service。
我们将Time Service的Role Instance数目指定为3,然后将其发布到Windows Azure平台。可以看到Echo Service指定的Input Endpoint,而所有的Internal Point都不会对外暴露。
总结:
Windows Azure Hosted Service为开发人员提供了Endpoint的配置机制。按照作用于可以分为Input Endpoint和Internal Endpoint,按照协议可以分为HTTP和TCP。我们可以通过指定Endpoint让Role Instance开发特定的端口,对外或对内发布服务。
Role之间的协同合作不仅仅可以通过之前介绍的Queue Storage来完成,也可以通过Internal Endpoint和TCP协议来完成。但相比Queue Storage来讲,使用Internal Endpoint的方式虽然不能实现对于瞬间大负载的吸收,但是却可以保证调用的高效性和及时性,所以也是一种非常有用的Role间调用方式。
本文摘自:徐子岩著的《实战Windows Azure 微软云计算平台技术详解》 电子工业出版社