65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Windows Server 上使用 Service Fabric 构建微服务

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.30/5 (5投票s)

2016 年 4 月 21 日

CPOL

5分钟阅读

viewsIcon

48350

downloadIcon

1111

使用 ASP.NET 5 和 Service Fabric SDK 在 Windows Server 2012 上使用 Service Fabric 构建微服务

引言

微服务架构风格正在迅速流行。有很多关于如何在 Java 和 Docker 容器中创建微服务的文档/示例,但在 .NET 中使用 Service Fabric 的却不多。本文将解释微服务的重要性,并澄清一些关于如何使用于 2015 年 11 月发布的 Azure Service Fabric 创建 ASP.NET Web API RESTful 微服务的困惑。文章还将附带示例代码作为参考。

背景

根据 Martin Fowler 和 James Lewis 在此撰写的论文,“微服务架构风格是一种将单个应用程序开发为一系列小型服务的方法,每个服务都运行在自己的进程中,并使用轻量级机制进行通信,通常是 HTTP 资源 API。这些服务围绕业务能力构建,并通过完全自动化的部署机制进行独立部署。这些服务只需最少程度的集中管理,可以采用不同的编程语言和数据存储技术。” 微服务架构风格具有以下优缺点。

优点

  • 使您能够选择最合适的技术栈。无需依赖框架来完成所有工作
  • 代码库要小得多,因此部署和构建时间大大缩短
  • 允许您发布更小的更改集
  • 更容易且成本效益更高,因为它们允许您只关注需要扩展的服务,而不是整个应用程序

缺点

  • 在初期增加新功能开发时间
  • 尽管 API 版本控制等技术可以缓解这一点,但可能会使应用程序重构变得困难
  • 由于有许多需要密切监控的活动部件,因此增加了额外的运营复杂性

为了使微服务正常工作,我们需要确保以下四点是必要的。它们也反映了上述定义和论文中列出的九个特性。

  1. 小型服务◦围绕业务能力组织
    • 运行在自己的进程中
  2. 服务发现
    • 服务在自己的进程中运行,并通过 HTTP 进行通信
    • 作为完全独立的组件部署
    • 智能端点和哑管道
  3. 自动化监控和管理◦基础设施自动化
    • 面向故障设计
    • 分散式治理
  4. 低摩擦部署
    • 可以单独扩展和更新

Azure Service Fabric 是一个用于可靠、超大规模、基于微服务的应用程序的平台。它既可以在本地通过 Windows Server 2012 使用,也可以在云端通过 Azure 使用。

微软在此提供了一个很好的教程 here,但它没有提供关于如何使用 ASP.NET Web API(大多数 .NET 开发者都熟悉)构建微服务的示例。ASP.NET Web API 也是当今 .NET 中创建 RESTful 服务最常用的。

准备开发环境

1. 先决条件

开发支持以下操作系统版本

  • Windows 7,PowerShell 3.0 或更高版本
  • Windows 8/Windows 8.1
  • Windows Server 2012 R2(用于本文代码测试)
  • Windows 10

2. 安装 Service Fabric 运行时、SDK 和工具

以下 Web Platform Installer 配置可用于 Service Fabric 开发

3. 启用 PowerShell 脚本执行

您需要从管理员权限的 PowerShell 命令窗口运行以下命令来启用 PowerShell 脚本执行。

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force -Scope CurrentUser

4. 如果本地集群不存在,请从 Service Fabric SDK 文件夹运行以下 PowerShell 脚本创建本地集群。

& "$ENV:ProgramFiles\Microsoft SDKs\Service Fabric\ClusterSetup\DevClusterSetup.ps1"

构建 RESTful ASP.NET Web API 无状态微服务

我找不到这样目的的教程。以下两个教程很接近,但并非完全符合要求,或者不易于理解。因此,我结合了以下两个教程,并使代码按我预期的方式工作,因为我想拥有无状态服务的功能,并且不想进行自托管。

高级步骤如下

步骤 1:以管理员身份启动 Visual Studio 2015,并创建一个名为 HelloWorld 的新 Service Fabric 应用程序项目。

步骤 2:创建一个名为 HelloWorldStateless 的无状态服务项目

步骤 3:以与 ASP.NET Web API 项目相同的方式创建文件夹结构。

步骤 4:DefaultController.cs 添加代码

namespace HelloWorldStateless.Controllers
{
    using System.Collections.Generic;
    using System.Web.Http;
    using System;

    [RoutePrefix("helloworld")]
    public class DefaultController : ApiController
    {
        // GET api/values
        [Route("values")]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [Route("values/{id}")]
        public string Get(int id)
        {
            string ret = Convert.ToString(id);
            return ret;
        }

        // POST api/values
        [Route("values")]
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        [Route("values/{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        [Route("values/{id}")]
        public void Delete(int id)
        {
        }
    }
}

步骤 5:在项目根目录下添加一个 Startup.cs 类,以注册路由、格式化程序和任何其他配置设置。添加 Json Formatter,以便输出为 Json 格式。

namespace HelloWorldStateless
{
    using Owin;
    using System.Web.Http;
    using System.Net.Http.Headers;

    public class Startup : IOwinAppBuilder
    {
        public void Configuration(IAppBuilder appBuilder)
        {
            HttpConfiguration config = new HttpConfiguration();
            config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
            config.MapHttpAttributeRoutes();

            FormatterConfig.ConfigureFormatters(config.Formatters);

            appBuilder.UseWebApi(config);
        }
    }
}

步骤 6:创建实现 ICommunicationListenerOwinCommunicationListener.cs

namespace HelloWorldStateless
{
    using System;
    using System.Fabric;
    using System.Fabric.Description;
    using System.Globalization;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Owin.Hosting;
    using Microsoft.ServiceFabric.Services.Communication.Runtime;

    public class OwinCommunicationListener : ICommunicationListener
    {
        private readonly IOwinAppBuilder startup;
        private readonly string appRoot;
        private IDisposable serverHandle;
        private string listeningAddress;
        private readonly ServiceInitializationParameters serviceInitializationParameters;

        public OwinCommunicationListener(string appRoot, 
        IOwinAppBuilder startup, ServiceInitializationParameters serviceInitializationParameters)
        {
            this.startup = startup;
            this.appRoot = appRoot;
            this.serviceInitializationParameters = serviceInitializationParameters;
        }

        public void Abort()
        {
            ServiceEventSource.Current.Message("Abort");

            this.StopWebServer();
        }

        public Task CloseAsync(CancellationToken cancellationToken)
        {
            ServiceEventSource.Current.Message("Close");
            this.StopWebServer();

            return Task.FromResult(true);
        }

        public Task<string> OpenAsync(CancellationToken cancellationToken)
        {
            EndpointResourceDescription serviceEndpoint = 
            serviceInitializationParameters.CodePackageActivationContext.GetEndpoint("ServiceEndpoint");
            int port = serviceEndpoint.Port;

            this.listeningAddress = String.Format(
                CultureInfo.InvariantCulture,
                "http://+:{0}/{1}",
                port,
                String.IsNullOrWhiteSpace(this.appRoot)
                    ? String.Empty
                    : this.appRoot.TrimEnd('/') + '/');

            this.serverHandle = WebApp.Start
            (this.listeningAddress, appBuilder => this.startup.Configuration(appBuilder));
            string publishAddress = this.listeningAddress.Replace
            ("+", FabricRuntime.GetNodeContext().IPAddressOrFQDN);

            ServiceEventSource.Current.Message("Listening on {0}", publishAddress);

            return Task.FromResult(publishAddress);
        }

        private void StopWebServer()
        {
            if (this.serverHandle != null)
            {
                try
                {
                    this.serverHandle.Dispose();
                }
                catch (ObjectDisposedException)
                {
                    // no-op
                }
            }
        }
    }
}

步骤 7:PackageRoot\ServiceManifest.xml 中配置 HTTP 端点

  <Resources>
    <Endpoints>
      <Endpoint Name="ServiceEndpoint" 
      Type="Input" Protocol="http" Port="8080" />
    </Endpoints>
  </Resources>

步骤 8:创建并返回 OwinCommunicationListener 的实例。

namespace HelloWorldStateless
{
    /// <summary>
    /// The FabricRuntime creates an instance of this class for each service type instance. 
    /// </summary>
    internal sealed class HelloWorldStateless : StatelessService
    {
        /// <summary>
        /// Optional override to create listeners (like tcp, http) for this service instance.
        /// </summary>
        /// <returns>The collection of listeners.</returns>
        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            return new[]
            {
                new ServiceInstanceListener(initParams => 
                new OwinCommunicationListener("webapp", new Startup(), initParams))
            };
        }
    }
}

步骤 9:通过 Web 浏览器运行并连接。

您现在可以构建和部署您的服务了。在 Visual Studio 中按 F5 键构建并部署应用程序。键入以下内容,URL 将回显值 9:

https://:8080/webapp/helloworld/values/9

步骤 10:从 Service Fabric Explorer 监控服务

这就是使用 Service Fabric 构建 ASP.NET Web API RESTful 微服务所需的所有工作。

以下是使用 Visual Studio 2015 在 Windows 2012 R2 上运行的 .NET 解决方案文件,带有 Service Fabric SDK - HelloWorld 解决方案

关注点

学习 Azure Service Fabric 非常有趣。构建微服务就像构建 ASP.NET Web API 应用程序一样简单。

历史

  • 2016 年 4 月 21 日:初始发布
© . All rights reserved.