API gateway/proxy 使用 Azure Service Fabric 部署的微服务模式

API gateway/proxy pattern for microservices deployed using Azure Service Fabric

看完 Azure Service Fabric 的 BUILD 会议视频后,我开始想象这可能如何适合我们当前的 microservice-based 架构。但是,有一件事我不完全确定我将如何解决 - API gateway/proxy.

考虑一个 less-than-trivial 微服务架构,其中您在 Azure Service Fabric 中有 N 个服务 运行 公开 REST 端点。在许多情况下,您希望将这些零散的 API 端点打包成一个 single-entry API 供消费者使用,以避免让他们直接连接到服务 fabric-instances。 Azure Service Fabric 解决方案似乎在各个方面都如此完整,以至于我想知道我是否错过了一些明显的东西,因为我没有看到在 BUILD 演讲中提到的功能范围内简单地解决这个问题的方法。

Vulcan 这样的服务旨在通过让服务在 etcd 中注册他们想要路由到它们的路径来解决这个问题。我猜想解决这个问题的一种方法可能是创建一个单独的有状态 Web 服务,其他服务可以向其注册自己,提供服务名称和它们需要路由到它们的路径。然后,有状态 Web 服务可以根据其状态将流量路由到正确的实例。不过,这似乎并不完全理想,比如在删除应用程序时删除路由,以及通常保持状态与集群内部署的服务同步。有没有人考虑过这个问题,或者知道如何在 Azure Service Fabric 中解决这个问题?

Azure Service Fabric 可以轻松实现此方案的标准体系结构:网关服务作为客户端连接的前端,所有 N 个后端服务都与前端网关通信。作为 Service Fabric 的一部分,有一些通信 API 堆栈可用,可以轻松地从客户端到服务以及服务本身进行通信。 Service Fabric 提供的通信 API 堆栈隐藏了发现、连接和重试连接的细节,以便您可以专注于实际的信息交换。使用 Service Fabric 通信 APIs 时,服务不必实施将其名称和端点注册到特定路由服务的机制,除了作为创建服务本身的一部分的常规步骤。通信 APIs 接收服务 URI 和分区键并自动解析并连接到正确的服务实例。 This article provides a good starting point to help make a decision with regards to which communication APIs will be best suited for your particular case depending on whether you are using Reliable Actors or Reliable Services, or protocols such as HTTP or WCF, or the choice of programming language that the services are written in. At the end of the article you will find links to more detailed articles and tutorials for different communication APIs. For a tutorial on communication in Web API services see this.

您需要执行此操作的服务 registration/discoverability 实际上已经存在。有一个称为命名服务的有状态系统服务,它基本上是服务实例和它们正在监听的端点的注册器。因此,当您启动一项服务(无状态或有状态)并在其上打开一些侦听器时,该地址会在命名服务中注册。

现在您需要填写的部分是用户与之互动的"gateway"。这不一定是有状态的,因为命名服务管理有状态的部分。但是你必须想出一个适合你的寻址方案,然后它将请求转发到正确的位置。基本上是这样的:

  1. 收到请求。
  2. 使用 NS 查找可以接受请求的服务。
  3. 将请求转发给它,并将响应返回给用户。
  4. 如果该服务不再存在,404。

一般来说,我们不喜欢规定任何有关您的服务如何相互通信的信息,但我们正在考虑将 HTTP 作为完整的内置解决方案来解决此问题的方法。

服务启动后,它会向结构命名服务注册其端点。然后,您可以使用 Fabric 客户端 API 向 Fabric 询问与注册服务名称关联的注册端点。

所以是的,就像您描述的情况一样,您将有一个网关接受传入的 URI 进行连接,然后使用该路径信息作为服务名称查找,然后在传入的之间创建代理连接请求和实际的内部端点位置。

看起来团队发布了一个展示如何执行此操作的示例:https://github.com/Azure/servicefabric-samples/tree/master/samples/Services/VS2015/WordCount

我想知道不是在 N+ 服务上公开 Rest,而是在服务结构内的所有地方使用默认通信堆栈(或尽可能在内部保持简单)。仅在边缘入口点将 REST 公开到结构中。使用一个标准的无状态网络 2.x api 来包装你的服务和参与者的结构代理,and/or 使用结构服务以同样的方式暴露休息。根据需要在面向前方的 Rest 服务中聚合您的 apis。不确定我是否看到需要额外的聚合器开销来进行命名重定向(也许我错过了这个想法)。那么它似乎只是一个用所需的命名空间(即外观模式)组织(和保护)休息端点的练习。

我们也为此实现了 HTTP 网关服务。为了确保我们可以为任何内部协议使用一个 HTTP 网关,我们使用 ASP.NET 5 中间件为基于 HTTP 的内部服务(如 ASP.NET WebAPI)实现了网关。它通过使用 ServicePartitionClient 和来自 CommunicationClientFactoryBase 的一些重试逻辑将请求从例如 /service 路由到内部 Service Fabric 地址,如 fabric:/myapp/myservice。

我们 open-sourced 这个中间件,你可以在这里找到它: https://github.com/c3-ls/ServiceFabric-HttpServiceGateway

该项目的 wiki 中还有更多文档。

从 Service Fabric 5.0 版开始,此功能内置于 http 端点。文档位于 https://azure.microsoft.com/en-us/documentation/articles/service-fabric-reverseproxy/

我们使用了一个名为 Traefik with amazing success. There is an Azure Service Fabric 的开源项目对其进行包装 - 它本质上是一个 GoLang exe,作为 Managed Executable.

部署到集群上

它支持断路器、加权循环 LB、路径和 header 版本路由(这对于托管多个 API 版本来说非常棒),不胜枚举。它有一个方便的门户来查看配置和运行状况统计信息。

它的真正威力在于您如何配置它。它是通过 ServiceManifest.xml 中的服务本身完成的。这允许您部署新服务并立即将它们路由到 - 无需更新路由 table 等

示例

<StatelessServiceType ServiceTypeName="WebServiceType">
  <Extensions>
      <Extension Name="Traefik">
        <Labels xmlns="http://schemas.microsoft.com/2015/03/fabact-no-schema">
          <Label Key="traefik.frontend.rule.example">PathPrefixStrip: /a/path/to/service</Label>
          <Label Key="traefik.enable">true</Label>
          <Label Key="traefik.frontend.passHostHeader">true</Label>
        </Labels>
      </Extension>
  </Extensions>
</StatelessServiceType>

强烈推荐!

我们正在使用带有网关模式的 SF,网关后面有大约 13 个服务。我们使用 SF 提供的内置 DNS 服务,请参阅:https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-dnsservice,这允许内部服务使用已知(SF 内部)DNS 名称为调用提供服务,包括内部服务的网关服务。有一些众所周知的 asp.net 核心网关(Ocelot、ProxyKit)可供使用,但我们推出了自己的网关。我们有一个外部负载均衡器来路由到 SF 中的多个网关实例。