Azure Service Bus Relay 深入分析和网络依赖

之前的一篇博文https://blogs.msdn.com/b/jianwu/archive/2014/10/15/azure-service-bus-service-bus-relay.aspx中,提到了Service Bus Relay的工作机制和实践方法,包括纯代码方式配置WCF/Service Bus endpoint和纯配置方式实现Service Bus Relay/WCF。实际运行过程中,虽然Service Bus Relay对本地的网络环境没有特殊要求,在最极端的情况下,只要客户端环境可以访问internet(http),Service Bus Relay就可以使得分布在不同地方的这样的客户端之间建立任意互联。但针对不同的 Service Bus Relay服务所选择的绑定协议和实现,Service Bus Relay对本地的网络还是有一定的要求的。本博客对Service Bus Relay服务所需的网络依赖以及Service Bus Relay的深入分析加以总结。

 

=1=. Service Bus Relay的网络依赖

如MSDN的解释:https://msdn.microsoft.com/en-us/library/ee732535.aspx

对于之前博文中选择的NetTcpRelayBinding方式所实现的Service Bus Relay(中继)服务,客户端需要允许端口9532和80上的对外连接。一般情况下,基于80端口的对外访问往往不会被本地IT限制,但在一些客户的网络环境下,基于9532端口的对外访问有可能会被禁止,因此,在那样的网络环境中,若要使得基于NetTcpRelayBinding方式的Service Bus Relay服务正常工作,需要事先联系本地网络管理员,开启对外端口9532的访问。

Binding

Transport Security

Port

NetTcpRelayBinding  (client/service)

either

9352/HTTP (9352/9353 if using Hybrid)

尽管如此,在开发Service Bus Relay服务中,开发者可以通过选择灵活的绑定方式和Service Bus服务的特殊网络设定,来规避上述端口的开启和关闭。

如:https://msdn.microsoft.com/en-us/library/microsoft.servicebus.connectivitymode.aspx

Member name

Description

AutoDetect

Auto-detect mode. Automatically selects  between the TCP, HTTP and HTTPS modes based on an auto-detection mechanism  that probes whether either connectivity option is available for the current  network environment. If both are available, the system will choose TCP by  default.

Http

HTTP mode. Listeners attempt an  HTTP connection followed by an HTTPS connection with the Windows Azure  Service Bus service and poll for messages. This might allow you to more  easily work around TCP port constraints.

Tcp

TCP mode (default). Listeners  create TCP connections to the Windows Azure Service Bus service to a  destination port in the range 9350 to 9354.

开发者可以通过配置ServiceBusEnvironment.SystemConnectivity.Mode ,来指定Service Bus Relay服务在运行过程中需要的本地网络端口。如下示例代码:ConnectivityMode.AutoDetect表示当前的Service Bus Relay服务会依次自动选择TCP(9532),http(80),https(443)来运行服务。因此,即使在某些网络环境中,对外的9532端口访问或https(443)端口被禁止,基于Service Bus Relay的服务还是可以自适应的选择http(80)来建立连接和暴露服务。

服务端代码:

            ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect;

            ServiceHost sh = new ServiceHost(typeof(ProblemSolver));

            sh.AddServiceEndpoint(
               typeof(IProblemSolver), new NetTcpBinding(),
               "net.tcp://localhost:9358/solver");

            sh.AddServiceEndpoint(
               typeof(IProblemSolver), new NetTcpRelayBinding(),
               ServiceBusEnvironment.CreateServiceUri("sb", "testsb1017", "solver"))
                .Behaviors.Add(new TransportClientEndpointBehavior
                {
                    TokenProvider = TokenProvider.CreateSharedSecretTokenProvider("owner", "×××××××××××××××××××/×××××=")
                });

            sh.Open();

客户端代码:

            ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect;

            var cf0 = new ChannelFactory<IProblemSolverChannel>(
                new NetTcpBinding(),
                new EndpointAddress("net.tcp://localhost:9358/solver"));

            Console.WriteLine("Trying to consume service through local WCF channel.");
            using (var ch0 = cf0.CreateChannel())
            {
                Console.WriteLine("{0}+{1}={2}",4,5,ch0.AddNumbers(4, 5));
            }

            var cf = new ChannelFactory<IProblemSolverChannel>(
                new NetTcpRelayBinding(),
                new EndpointAddress(ServiceBusEnvironment.CreateServiceUri("sb", "testsb1017", "solver")));

            cf.Endpoint.Behaviors.Add(new TransportClientEndpointBehavior { TokenProvider = TokenProvider.CreateSharedSecretTokenProvider("owner", "×××××××××××/×××××××××××=") });

            Console.WriteLine("Trying to consume service through Service Bus channel.");
            using (var ch = cf.CreateChannel())
            {
                Console.WriteLine("{0}+{1}={2}", 4, 5, ch.AddNumbers(4, 5));
            }

 除了选择自适应的对外服务端口ConnectivityMode.AutoDetect之外,开发者也可以由ConnectivityMode.HTTP/TCP直接指定Http或者TCP端口来建立service bus relay服务。这项端口设定能很好的解决一些复杂网络环境问题。

还有一些情况下,当网络环境中必须使用网络代理才能访问internet时,开发者也需要在Service Bus Relay服务中处理本地的网络代理及其验证问题,一种常用的实现方法如下。该方法适用于service bus relay的服务端和客户端。

            System.Net.WebRequest.DefaultWebProxy = System.Net.WebRequest.GetSystemWebProxy();
            System.Net.WebRequest.DefaultWebProxy.Credentials = CredentialCache.DefaultCredentials;

            ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect;

            ServiceHost sh = new ServiceHost(typeof(ProblemSolver));

            sh.AddServiceEndpoint(
               typeof(IProblemSolver), new NetTcpBinding(),
               "net.tcp://localhost:9358/solver");

            sh.AddServiceEndpoint(
               typeof(IProblemSolver), new NetTcpRelayBinding(),
               ServiceBusEnvironment.CreateServiceUri("sb", "testsb1017", "solver"))
                .Behaviors.Add(new TransportClientEndpointBehavior
                {
                    TokenProvider = TokenProvider.CreateSharedSecretTokenProvider("owner", "×××××××××××××××/××××××××××××××××××××8=")
                });

            sh.Open();

基于上述Service Bus Relay运行过程中的网络依赖,下面加以验证:

1. 下载并运行Network Monitor工具,跟踪service bus relay服务的网络情况:

2. 在不添加ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect;时,https://blogs.msdn.com/b/jianwu/archive/2014/10/15/azure-service-bus-service-bus-relay.aspx中的服务端很明显的使用端口9350来对外建立连接,暴露服务到internet。

3. 当对本地的网络加以限制,禁止端口9350-9354上的对外连接时。

4. https://blogs.msdn.com/b/jianwu/archive/2014/10/15/azure-service-bus-service-bus-relay.aspx中的示例中添加ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect,然后服务端和客户端都能够正常运行,其运行所用的网络端口是80.这与ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect的设计是一致的。

 =2=. Service Bus Relay服务的深入分析

如前面的博文所介绍,Service Bus Relay(中继)服务在开发技巧上,与传统的WCF非常类似。因此,对于Service Bus Relay的开发,可以借鉴WCF服务中的一些特性来深入跟踪和分析,比如WCF Tracing功能。

关于WCF Tracing功能,可以参考:https://msdn.microsoft.com/en-us/library/ms733025(v=vs.110).aspx

在WCF服务中,一旦打开的Tracing功能,该WCF服务的一切活动都会被记录到Tracing日志中,于是,WCF的连接问题、性能问题等等都可以通过Tracing日志来分析和优化。

在Service Bus Relay服务中,开发者也可以开启Tracing功能,来深入跟踪和分析Service Bus Relay的服务(客户)端的实时表现。

如以下相同的配置可适用于服务端和客户端:

......

<startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
 
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Verbose"
              propagateActivity="true">
        <listeners>
          <add name="traceListener"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData="Traces.svclog" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

</configuration>

 通过上述配置开启了Tracing功能之后,基于Azure Service Bus Relay的服务状态可以随时通过查看Tracing日志,如Traces.svclog来分析了。

很方便吧!开发者可以通过本文中的代码实践一下,进一步体会Service Bus Relay的优点和便捷。