Service Fabric 与 Ocelot 集成
概要
云应用程序通常都需要使用前端网关,为用户、设备或其他应用程序提供同一个入口点。 在 Service Fabric 中,网关可以是任意无状态服务(如 ASP.NET Core 应用程序) 。
本文介绍了如何将Ocelot用作 Service Fabric 应用程序的网关。Ocelot直接与 Service Fabric 集成,以便可以使用一组丰富的路由规则向后端 Service Fabric 服务发布 API。
架构
常见 Service Fabric 体系结构使用单页 Web 应用程序,向公开 HTTP API 的后端服务发出 HTTP 调用请求。
随着应用程序越来越复杂,必须向大量后端服务发布API的网关亦是如此。Ocelot旨在通过路由规则、访问控制、速率限制、监视、事件日志记录和响应缓存来处理复杂 API,最大限度地减少用户需要执行的操作。 Ocelot支持 Service Fabric 服务发现、分区解析和副本选择,从而智能地将请求直接路由到 Service Fabric 中的后端服务,用户无需编写自己的无状态 API 网关。
应用程序方案
Service Fabric 中的服务可以是无状态服务,也可以是有状态服务,可采用以下三种方案之一进行分区:单独分区、Int64 范围分区和已命名分区。 必须确定特定服务实例的具体分区,才能解析服务终结点。解析服务终结点时,必须指定服务实例名称(例如,fabric:/myapp/myservice)以及服务的具体分区,但单独分区情况除外。
Ocelot可与无状态服务、有状态服务和任何分区方案的任意组合配合使用。
https://ocelot.readthedocs.io/en/latest/features/servicefabric.html
如果您正在使用无状态/Guest服务,则ocelot将能够通过命名服务进行代理而无需其他任何操作。但是,如果您正在使用有状态服务/ actor服务,则必须使用客户端请求发送PartitionKind和PartitionKey查询字符串值。
以下示例展示如何设置一个ReRoute以便在在Service Fabric中工作。 最重要的是ServiceName,它由Service Fabric应用程序名称和特定服务名称组成的。 我们还需要将UseServiceDiscovery设置为true,并在GlobalConfiguration中设置ServiceDiscoveryProvider。 这里的例子显示了一个典型的配置。 它假定Service Fabric在本地主机上运行,并且命名服务位于19081端口上。
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/values",
"UpstreamPathTemplate": "/servicea/api/values",
"UpstreamHttpMethod": [ "Get"],
"DownstreamScheme": "http",
"ServiceName": "NanoFabric_ServiceFabric/ServiceA",
"UseServiceDiscovery": true,
"AuthenticationOptions": {
"AuthenticationProviderKey": "apikey",
"AllowedScopes": []
},
"AddHeadersToRequest": {
"claims_City": "Claims[City] > value > |",
"claims_State": "Claims[State] > value > |"
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/{route}",
"UpstreamPathTemplate": "/serviceoauth/{route}",
"UpstreamHttpMethod": [ "Get", "Options", "Post" ],
"DownstreamScheme": "http",
"ServiceName": "NanoFabric_ServiceFabric/ServiceOAuth",
"UseServiceDiscovery": true
}
],
"GlobalConfiguration": {
"RequestIdKey": "OcRequestId",
"AdministrationPath": "/administration",
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 19081,
"Type": "ServiceFabric"
}
}
}
原理就是借助 Service Fabric 中内置的反向代理,Service Fabric 群集中运行的微服务可以发现包含 http 终结点的其他服务,并与之通信。
微服务通信模型
Service Fabric 中的微服务在群集中的部分节点上运行,可以出于各种原因在这些节点之间迁移。 因此,微服务的终结点可能会动态变化。 若要发现群集中的其他服务并与之通信,微服务必须完成以下步骤:
l 通过命名服务解析服务位置。
l 连接到服务。
l 在实现服务解析以及在发生连接故障时应用的重试策略的循环中,包装上述步骤
使用反向代理通信
反向代理是在每个节点上运行的服务,用于代表客户端服务处理终结点解析、自动重试及其他连接故障。 可以将反向代理配置为,一边处理客户端服务的请求,一边应用各种策略。 借助反向代理,客户端服务可以使用任意客户端 HTTP 通信库,无需服务中有特殊的解析和重试逻辑。
反向代理在本地节点上公开一个或多个终结点,以供客户端服务用来向其他服务发送请求。
反向代理使用特定的统一资源标识符 (URI) 格式来识别传入请求应该转发到的服务分区:
http(s)://<Cluster FQDN | internal IP>:Port/<ServiceInstanceName>/<Suffix path>?PartitionKey=<key>&PartitionKind=<partitionkind>&ListenerName=<listenerName>&TargetReplicaSelector=<targetReplicaSelector>&Timeout=<timeout_in_seconds>
l http(s): 可以将反向代理配置为接受 HTTP 或 HTTPS 流量。 对于 HTTPS 转发,在设置反向代理侦听 HTTPS 后,请参阅使用反向代理连接到安全服务。
l 群集的完全限定域名 (FQDN) | 内部 IP: 对于外部客户端,可以配置反向代理,以便可以通过群集域(例如 mycluster.eastus.cloudapp.azure.com)访问反向代理。 默认情况下,反向代理在每个节点上运行。 对于内部流量,可在本地主机或任意内部节点 IP(例如 10.0.0.1)上访问反向代理。
l Port:为反向代理指定的端口,例如 19081。
l ServiceInstanceName: 在不使用“fabric:/”方案的情况下尝试访问的已部署服务实例的完全限定名称。 例如,若要访问 fabric:/myapp/myservice/ 服务,可以使用 myapp/myservice。
l 服务实例名称要区分大小写。 若 URL 中的服务实例名称大小写不同,则会导致请求失败,并显示 404(未找到)。
l 后缀路径: 要连接到的服务的实际 URL 路径,例如 myapi/values/add/3。
l PartitionKey: 对于分区服务,这是针对要访问的分区计算出的分区键。 请注意,这不是分区 ID GUID。 对于使用单独分区方案的服务,此参数不是必需的。
l PartitionKind: 服务分区方案。 该方案可以是“Int64Range”或“Named”。 对于使用单独分区方案的服务,此参数不是必需的。
l ListenerName 服务中的终结点采用以下形式:{"Endpoints":{"Listener1":"Endpoint1","Listener2":"Endpoint2" ...}}。 当服务公开了多个终结点时,此参数标识应将客户端请求转发到的终结点。 如果服务只有一个侦听器,则可以省略此项。
l TargetReplicaSelector 这指定应当如何选择目标副本或实例。
l 当目标服务为有状态服务时,TargetReplicaSelector 可以是下列其中一项:“PrimaryReplica”、“RandomSecondaryReplica”或“RandomReplica”。 如果未指定此参数,默认值为“PrimaryReplica”。
l 当目标服务为无状态服务时,反向代理将选择服务分区的一个随机实例来将实例转发到其中。
l Timeout: 此参数指定反向代理针对服务创建的 HTTP 请求(代表客户端请求)的超时。 默认值为 60 秒。 这是一个可选参数
Ocelot充当微服务和外部客户端之间的网络边界,可以进行网络地址转换并将外部请求转发到内部的 IP:端口终结点。 要允许外部客户端直接访问微服务的终结点,必须先将Ocelot配置为将流量转发到群集中服务使用的每个端口。 另外,大多数微服务(尤其是有状态微服务)并不驻留在群集的所有节点上。 这些微服务在故障转移时可在节点之间移动。 在这种情况下,负载均衡器无法有效确定要将流量转发到的副本的目标节点位置。
可以在Ocelot中直接配置反向代理的端口,而无需配置单个服务的端口。 这种配置可让群集外部的客户端使用反向代理访问群集内部的服务,无需经过额外的配置。
通过Ocelot可从群集外部访问群集中公开 HTTP 终结点的所有微服务。 这意味着微服务设计为内部的可能会被确定的恶意用户发现。这潜在地提供可被利用的严重漏洞;例如:
恶意用户可以通过反复调用没有足够强化的攻击面的内部服务来发起拒绝服务攻击。
恶意用户可能会将格式错误的数据包传送到内部服务,从而导致意外行为。
设计为内部的服务可能会返回不应公开给群集外部的服务的私有或敏感信息,从而将此敏感信息泄露给恶意用户。在网关上开启身份认证、流控等措施来解决安全问题。
反向代理是一种可选的 Azure Service Fabric 服务,有助于在 Service Fabric 群集中运行的微服务发现包含 http 终结点的其他服务,并与之通信,在创建新的 Service Fabric 群集时,Azure 门户提供了一个启用反向代理的选项。 无法通过门户升级现有群集来使用反向代理。
我们的示例项目
我们的示例项目代码放在 https://github.com/geffzhang/NanoFabric-ServiceFabric ,解决方案中包含了一个后端服务ServiceA,是个无状态的服务,一个Ocelot 网关和一个Identity Server 4的认证服务,在网关上集成了IdentityServer4 的认证服务 ,由网关负责认证,认证完成将Claims 转换为HttpHeader 中转发到下游服务。
服务实例A是一个无状态的服务
我们将其配置为运行2个实例。在Application Parameters中,我将* _InstanceCount参数值设置为2:
让Service Fabric选择端口,我们将从端点中删除该Port
属性:
当开发机器上的无法实现在同一端口上运行多个实例,如果填写了Port 属性,_InstanceCount只能保持为1. 让端口保持动态,我们可以在本地实现服务的伸缩。
部署自己的网关
部署自己的网关这听起来像是需要做很多工作,实际上非常简单。我们需要与反向代理相同的行为,只需要更多的控制。在我们这个开源的开发的世界,这个问题已经解决了,我们有开源的API网关Ocelot http://threemammals.com/ocelot ,而且做得非常好,可以完美的和Service Fabric 一起工作。
我们将添加一个新的空aspnet core无状态服务
让我们配置我们的端点。您需要知道我们的网关在哪里,所以我们给它一个特定的端口。在ServiceManifest中,设置端点的端口:
<Endpoint Protocol="http" Name="ServiceEndpoint" Type="Input" Port="8492" />
网关是系统的入口点,必须保持可用状态。我们在每个节点上部署它。修改ApplicationParameters中添加的参数NanoFabricGateway_InstanceCount。确保生产部署的值为-1。
<Parameter Name="NanoFabricGateway_InstanceCount" Value="-1"/>
请注意,如果部署到本地群集,则无法在同一端口上运行多个服务实例。对于本地开发群集,要么将其保留为1,要么让端口为动态。
代码实现上并没有什么特殊的地方。
配置Azure负载均衡器
当然,没有人想通过端口访问您的网站8492。接下来,我们需要设置负载均衡器以指向我们新部署的网关。在部署在azure上的新集群(可以参考这篇文章使用Powershell https://noelbundick.com/posts/service-fabric-cluster-quickstart/ ),现有AppPortLBRule1端口80。编辑它,并将后端端口更改为指向网关端口:8492在我的情况下。同时请注意,Load Balancer定义了一个Health Probe。如果健康检测未成功,则负载均衡器将假定后端服务池不健康,并且不会重定向您的请求。
参考文章:
https://docs.microsoft.com/zh-cn/azure/service-fabric/service-fabric-api-management-overview
https://ocelot.readthedocs.io/en/latest/features/servicefabric.html
Service Fabric 与 Ocelot 集成的更多相关文章
- 重磅消息-Service Fabric 正式开源
微软的Azure Service Fabric的官方博客在2017.3.24日发布了一篇博客 Service Fabric .NET SDK goes open source ,介绍了社区呼声最高的S ...
- 手动造轮子——为Ocelot集成Nacos注册中心
前言 近期在看博客的时候或者在群里看聊天的时候,发现很多都提到了Ocelot网关的问题.我之前也研究过一点,网关本身是一种通用的解决方案,主要的工作就是拦截请求统一处理,比如认证.授权.熔断. ...
- Azure Service Fabric 开发环境搭建
微服务体系结构是一种将服务器应用程序构建为一组小型服务的方法,每个服务都按自己的进程运行,并通过 HTTP 和 WebSocket 等协议相互通信.每个微服务都在特定的界定上下文(每服务)中实现特定的 ...
- 人人都可以开发高可用高伸缩应用——论Azure Service Fabric的意义
今天推荐的文章其实是微软的一篇官方公告,宣布其即将发布的一个支撑高可用高伸缩云服务的框架--Azure Service Fabric. 前两天,微软Azure平台的CTO Mark Russinovi ...
- 期待微软平台即服务技术Service Fabric 开源
微软的Azure Service Fabric的官方博客在3.24日发布了一篇博客 Service Fabric .NET SDK goes open source ,介绍了社区呼声最高的Servic ...
- Ocelot 集成Butterfly 实现分布式跟踪
微服务,通常都是用复杂的.大规模分布式集群来实现的.微服务构建在不同的软件模块上,这些软件模块,有可能是由不同的团队开发.可能使用不同的编程语言来实现.有可能布在了几千台服务器,横跨多个不同的数据中心 ...
- 微服务框架之微软Service Fabric
常见的微服务架构用到的软件&组件: docker(成熟应用) spring boot % spring cloud(技术趋势) Service Fabric(属于后起之秀 背后是微软云的驱动) ...
- Service Fabric
Service Fabric 开源 微软的Azure Service Fabric的官方博客在3.24日发布了一篇博客 Service Fabric .NET SDK goes open source ...
- Service Fabric基本概念: Node, Application, Service, Partition/Replicas
作者:张鼎松 (Dingsong Zhang) @ Microsoft 在上一节中,为大家简明扼要的介绍了微软针对现代分布式系统在Azure上实现的相关服务组件.紧接上文内容,本节将为大家介绍Azur ...
随机推荐
- Python基本类常用方法
数学函数 abs(x) 返回数字的绝对值,如abs(-10) 返回 10 ceil(x) 返回数字的上入整数,如math.ceil(4.1) 返回 5 cmp(x, y)如果 x < y 返回 ...
- Oracle-05:伪表dual
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 此乃这张表里的全部字段信息,此表无法做修改操作 为什么有伪表这个概念?????????? 因为sql92的一个 ...
- HTML学习之制作导航网页
前言 今天用HTML写了一个网址导航,源代码如下: <html> <head> <title>网址导航</title> </head> &l ...
- springMVC引入Validation详解
本文简单介绍如何引入validation的步骤,如何通过自定义validation减少代码量,提高生产力.特别提及:非基本类型属性的valid,GET方法的处理,validation错误信息的统一re ...
- 自研网关纳管Spring Cloud(一)
摘要: 本文主要从网关的需求,以及Spring Cloud Zuul的线程模型和源码瓶颈分析结合,目前最近一段时间自研网关中间件纳管Spring Cloud的经验汇总整理. 一.自研网关纳管Sprin ...
- 7-20 jquery遍历节点,bootstrap模态框绑定事件和解绑,mock.js,model.urlroot,id,打基础
7-19 1:$(event.target).parents().filter("tr").find("host-name") 为什么选择不到别的host-na ...
- java的Junit的用法(转发)
初级https://blog.csdn.net/andycpp/article/details/1327147/ 中级https://blog.csdn.net/andycpp/article/det ...
- java.lang.IllegalArgumentException异常 返回值类型的问题
java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return usi ...
- 使用Eclipse远程调试
在一般的开发中,有事因为项目需要,测试环境是在Linux下,这是如果出现异常或者bug,调试起来都是很费劲的,如果你还在为这个头疼,那就好好看接下来的总结 1,启动改程序时,不论是脚本启动,还是tom ...
- CString 转化成 const char* 类型
写程序的时候经常会遇到无法将“CString”转换为“const char *”的错误,这里我找到了一个解决办法,与大家分享下: CString cs = _T("); ) * ; char ...