【愚公系列】2022年07月 .NET架构班 085-微服务专题 Abp vNext微服务网关

举报
愚公搬代码 发表于 2022/07/31 21:30:29 2022/07/31
【摘要】 一、微服务网关 1.微服务网关概念API网关是一个服务器,是系统对外的唯一入口。API网关封装了系统内部架构,为每个客户端提供一个定制的API。API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能,通常网关也是提供REST/HTTP的访问API。服务端通过API网关注册和管理服务。 2.微服务网关技术选型—KongTraefikAmbas...

一、微服务网关

1.微服务网关概念

API网关是一个服务器,是系统对外的唯一入口。API网关封装了系统内部架构,为每个客户端提供一个定制的API。API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能,通常网关也是提供REST/HTTP的访问API。服务端通过API网关注册和管理服务。

2.微服务网关技术选型

Kong Traefik Ambassador Tyk Zuul
基本
主要用途 企业级API管理 微服务网关 微服务网关 微服务网关 微服务网关
学习曲线 适中 simple simple 适中 simple
成本 开源/企业版 开源 开源/pro 开源/企业版 开源
社区star 20742 21194 1719 4299 7186
配置
配置语言 Admin Rest api, Text file(nginx.conf等) TOML YAML(kubernetes annotation) Tyk REST API REST API,YAML静态配置
配置端点类 命令式 声明式 声明式 命令式 命令式
拖拽配置 yes no no no no
管理模式 configurable decentralised, self-service decentralised, self-service decentralised, self-service decentralised self-service
部署
kubernetes 适中(k8s yaml,helm chart) easy easy 适中(k8s yaml,helm chart) 适中(k8s yaml,helm chart)
Cloud IASS high easy N/A easy easy
Private Data Center high easy N/A easy easy
部署模式 全丝雀(企业版) 全丝雀 金丝雀,shadow 金丝雀 全丝雀
state postgres,cassandra kubernetes kubemetes redis 内存文件
可扩展性
扩展功能 插件 自己实现 插件 插件 自己实现
扩展方法 水平 水平 水平 水平 水平
功能
服务发现 动态 动态 动态 动态 动态
协议 http,https,websocket http,https,grpc,websocket http,https,grpc,websocket http,https,grpc,websocket http,https
基于 kong+nginx traefik envoy tyk zuul
ssl终止 yes yes yes yes no
websocket yes yes yes yes no
routing host,path,method host,path host,path,header host,path
限流 yes no yes yes 需要开发
熔断 yes yes no yes 需要其他组件
重试 yes yes no yes yes
健康检查 yes no no yes yes
负载均衡算法 轮询,哈希 轮询,加权轮询 加权轮询 轮询 轮询,随机,加权轮询,自定义
权限 Basic Auth, HMAC, JWT, Key, LDAP, OAuth 2.0,PASETO, plus paid Kong Enterprise options like OpenlD Connect basic yes HMAC, JWT,Mutua TLS,OpenlD Connect,基本身份验证,LDAP,社交OAuth(例如GPlus,Twitter, Github)和传统 基本身份验证提供程序 开发实现
tracing yes yes yes yes 需要其他组件
istio集成 no no yes no no
dashboard yes yes grafana,Prometheus yes no

核心解释:

  • Netflix:Zuul +java实现
  • Kong:nginx +lua脚本实现
  • Tyk:go语言开发,收费版本
  • Ocelot:aspnetcore开发的

2.微服务网关Ocelot

Ocelot文档地址:

中文文档:http://www.jessetalk.cn/2018/03/19/net-core-apigateway-ocelot-docs/

英文文档:https://ocelot.readthedocs.io/en/latest/introduction/gettingstarted.html

2.1 Ocelot是什么

简单的来说Ocelot是一堆的asp.net core middleware组成的一个管道。当它拿到请求之后会用一个request builder来构造一个HttpRequestMessage发到下游的真实服务器,等下游的服务返回response之后再由一个middleware将它返回的HttpResponseMessage映射到HttpResponse上。

2.2 Ocelot内部概念

  • 上游:Ocelot为上游:Upstream
  • 下游:Ocelot下面映射的服务为下游:Downstream

2.3 Ocelot主要功能

  • 路由
    • 接受客户端请求
    • 奖客户端请求转换成下游地址
    • 调用下游服务,并返回结果
    • 将下游服务返回的结果返回到前端
  • 认证
  • 授权
  • 负载均衡
  • 链路监控
  • 限流
  • 熔断降级
  • 请求聚合
  • Service Fabric
  • 其他功能

3.微服务网关Ocelot集成在.NET Core

3.1 Ocelot网关环境

  • asp.net core 6.0
  • Ocelot
  • 团队微服务
  • ocelot.json

3.2 Ocelot配置步骤

1、创建一个空的 asp.net core 6.0项目,并把项目转ABP框架形式
详细部署ABP web项目链接:https://codeboy.blog.csdn.net/article/details/122811497
2、通过nuget安装Ocelot
在这里插入图片描述

3、创建Ocelot配置文件ocelot.json

{
	"Routes": [],
	"GlobalConfiguration": {
		"BaseUrl": "https://api.mybusiness.com"
	}
}	

要特别注意一下BaseUrl是我们外部暴露的Url,比如我们的Ocelot运行在http://150.150.1.1的一个地址上,但是前面有一个 nginx绑定了域名http://api.like.cn,那这里我们的BaseUrl就是 http://api.like.cn

4、加载ocelot.json配置文件,并加载配置文件

public override void ConfigureServices(ServiceConfigurationContext context)
{
    var configuration = context.Services.GetConfiguration();
    // 1、添加ocelot
    context.Services.AddOcelot(configuration);
}

6、配置Ocelot中间件

public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
    var app = context.GetApplicationBuilder();

    app.UseCorrelationId();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAbpClaimsMap();

    // 2、使用ocelot
    app.UseOcelot().Wait();
}

3.2 Ocelot配置文件

{
    "DownstreamPathTemplate": "/",
    "UpstreamPathTemplate": "/",
    "UpstreamHttpMethod": [
   	 	"Get"
    ],
    "AddHeadersToRequest": {},
    "AddClaimsToRequest": {},
    "RouteClaimsRequirement": {},
    "AddQueriesToRequest": {},
    "RequestIdKey": "",
    "FileCacheOptions": {
	    "TtlSeconds": 0,
	    "Region": ""
    },
    "ReRouteIsCaseSensitive": false,
    "ServiceName": "",
    "DownstreamScheme": "http",
    "DownstreamHostAndPorts": [
	    {
	    	"Host": "localhost",
	    	"Port": 51876,
	    }
    ],
    "QoSOptions": {
	    "ExceptionsAllowedBeforeBreaking": 0,
	    "DurationOfBreak": 0,
	    "TimeoutValue": 0
    },
    "LoadBalancer": "",
    "RateLimitOptions": {
	    "ClientWhitelist": [],
	    "EnableRateLimiting": false,
	    "Period": "",
	    "PeriodTimespan": 0,
	    "Limit": 0
    },
    "AuthenticationOptions": {
	    "AuthenticationProviderKey": "",
	    "AllowedScopes": []
    },
    "HttpHandlerOptions": {
	    "AllowAutoRedirect": true,
	    "UseCookieContainer": true,
	    "UseTracing": true
    },
    "UseServiceDiscovery": false
}
  • Downstream是下游服务配置
  • UpStream是上游服务配置
  • Aggregates 服务聚合配置
  • ServiceName, LoadBalancer, UseServiceDiscovery 配置服务发现
  • AuthenticationOptions 配置服务认证
  • RouteClaimsRequirement 配置Claims鉴权
  • RateLimitOptions为限流配置
  • FileCacheOptions 缓存配置
  • QosOptions 服务质量与熔断
  • DownstreamHeaderTransform头信息转发

3.2.1 路由基本使用

"Routes":[
	{
		"DownstreamPathTemplate": "/api/Teams",
		"DownstreamScheme": "https",
		"DownstreamHostAndPorts": [
			{
			"Host": "localhost",
			"Port": 5001,
			}
		],
		"UpstreamPathTemplate": "/AggregateService",
		"UpstreamHttpMethod": [ "Get"]
	}
]
  • DownstreamPathTemplate:下游路径模板
  • DownstreamScheme:下游服务http schema
  • DownstreamHostAndPorts:下游服务的地址,如果使用LoadBalancer的话这里可以填多项
  • UpstreamPathTemplate: 上游也就是用户输入的请求Url模板
  • UpstreamHttpMethod: 上游请求http方法,可使用数组

3.2.2 路由负载均衡

"Routes":[
{
    "DownstreamPathTemplate": "/api/Teams",
    "DownstreamScheme": "https",
    "DownstreamHostAndPorts": [
            {
                "Host": "localhost",
                "Port": 5005,
            },
            {
                "Host": "localhost",
                "Port": 5003,
            }
        ],
    "LoadBalancerOptions": {
        "Type": "LeastConnection"
    },
    "UpstreamPathTemplate": "/AggregateService",
    "UpstreamHttpMethod": [ "Put", "Delete" ]
}
]    

LoadBalancer将决定负载均衡的算法

  • LeastConnection – 最小活跃数算法
  • RoundRobin – 轮询算法
  • NoLoadBalance – 总是发往第一个请求或者是服务发现

3.3 Ocelot集成在.NET Core上

3.3.1 单路由配置

1、通过nuget下载Ocelot.Provider.Consul

2、添加consul依赖注入

public void ConfigureServices(IServiceCollection services)
        {
            // 1、添加网关Ocelot到ioc容器
            services.AddOcelot().AddConsul();
        }

3、路由consul配置

"Routes":[
	{
        "DownstreamPathTemplate": "/api/teams",
        "DownstreamScheme": "https",
        "UpstreamPathTemplate": "/AggregateService",
        "UpstreamHttpMethod": [ "Get" ],
        "ServiceName": "AggregateService",
        "LoadBalancerOptions": {
            "Type": "LeastConnection"
        },
	}
]

3.3.2 多路由配置

1、创建ocelot.team.json,ocelot.member.json文件

2、配置动态加载ocelot.json配置文件

webBuilder.ConfigureAppConfiguration((hostingContext, config) =>
                    {
                        config
                            // .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
                            // .AddJsonFile("appsettings.json", true, true)
                            // .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
                            .AddOcelot(hostingContext.HostingEnvironment);
                        // .AddEnvironmentVariables();
                    });

自动的加载配置文件,然后进行合并,主要用于大项目配置

3、ocelot依赖注入配置

public void ConfigureServices(IServiceCollection services)
        {
            // 1、添加网关Ocelot到ioc容器
            services.AddOcelot()}

3.3.3 路由聚合请求

{
    "Routes": [
    {
    "DownstreamPathTemplate": "/",
    "UpstreamPathTemplate": "/laura",
    "UpstreamHttpMethod": [
   		 "Get"
    ],
    "DownstreamScheme": "http",
    "DownstreamHostAndPorts": [
        {
            "Host": "localhost",
            "Port": 51881
        }
    ],
    "Key": "Laura"
    },
    {
    "DownstreamPathTemplate": "/",
    "UpstreamPathTemplate": "/tom",
    "UpstreamHttpMethod": [
    "Get"
    ],
    "DownstreamScheme": "http",
    "DownstreamHostAndPorts": [
    {
    "Host": "localhost",
    "Port": 51882
    }
    ],
    "Key": "Tom"
    }
    ],
    "Aggregates": [
        {
        "ReRouteKeys": [
            "Tom",
            "Laura"
        ],
        "UpstreamPathTemplate": "/"
        }
    ]
}

当我们请求/的时候,会将/tom和/laura两个结果合并到一个response返回

{"Tom":{"Age": 19},"Laura":{"Age": 25}}

需要注意的是:

  • 聚合服务目前只支持返回json
  • 目前只支持Get方式请求下游服务
  • 任何下游的response header并会被丢弃
  • 如果下游服务返回404,聚合服务只是这个key的value为空,它不会返回404

有一些其它的功能会在将来实现

  • 下游服务很慢的处理
  • 做一些像 GraphQL的处理对下游服务返回结果进行处理
  • 404的处理

3.3.4 路由服务质量与熔断

nuget安装包:Ocelot.Provider.Polly

1、在ocelot上添加熔断

public void ConfigureServices(IServiceCollection services)
        {
            // 1、添加网关Ocelot到ioc容器
            services.AddOcelot(new ConfigurationBuilder().AddJsonFile("ocelot.aggregate.json").Build())
                .AddConsul()
                .AddPolly();
        }

2、添加熔断配置

熔断的意思是停止将请求转发到下游服务。当下游服务已经出现故障的时候再请求也是功而返,并且增加下游服务器和API网关的负担。这个功能是用的Pollly来实现的,我们只需要为路由做一些简单配置即可

"Routes": [
"QoSOptions": {
    "ExceptionsAllowedBeforeBreaking":3,
    "DurationOfBreak":500,
    "TimeoutValue":5000
}
]    
  • ExceptionsAllowedBeforeBreaking 允许多少个异常请求
  • DurationOfBreak 熔断的时间,单位为毫秒
  • TimeoutValue 如果下游请求的处理时间超过多少则自动将请求设置为超时

3.3.5 路由限流

"Routes": [
	"RateLimitOptions": {
	    "ClientWhitelist": [],
	    "EnableRateLimiting": true,
	    "Period": "5m",
	    "PeriodTimespan": 1,
	    "Limit": 1
	}
]
  • ClientWihteList 白名单
  • EnableRateLimiting 是否启用限流
  • Period 统计时间段:1s, 5m, 1h, 1d 多长时间内只能请求多少次
  • PeroidTimeSpan 多少秒之后客户端可以重试
  • Limit 在统计时间段内允许的最大请求数量

在 GlobalConfiguration下我们还可以进行以下配置

"RateLimitOptions": {
  "DisableRateLimitHeaders": false,
  "QuotaExceededMessage": "Customize Tips!",
  "HttpStatusCode": 999,
  "ClientIdHeader" : "Test"
}
  • Http头 X-Rate-Limit 和 Retry-After 是否禁用
  • QuotaExceedMessage 当请求过载被截断时返回的消息
  • HttpStatusCode 当请求过载被截断时返回的http status
  • ClientIdHeader 用来识别客户端的请求头,默认是 ClientId

3.3.5 路由缓存

Ocelot可以对下游请求结果进行缓存 ,目前缓存的功能还不是很强大。它主要是依赖于CacheManager 来实现的,我们只需要在路由下添加以下配置即可

"Routes": [
"FileCacheOptions": { "TtlSeconds": 15, "Region": "somename" }
    }

Region是对缓存进行的一个分区,我们可以调用Ocelot的 administration API来移除某个区下面的缓存 。

3.3.6 路由认证(Identity Server4)

1、Identity Server Bearer Tokens

添加Identity Server的认证也是一样

public void ConfigureServices(IServiceCollection services)
{
    var authenticationProviderKey = "TestKey";
    var options = o =>
        {
            o.Authority = "https://whereyouridentityserverlives.com";
            o.ApiName = "api";
            o.SupportedTokens = SupportedTokens.Both;
            o.ApiSecret = "secret";
        };

    services.AddAuthentication()
        .AddIdentityServerAuthentication(authenticationProviderKey, options);

    services.AddOcelot();
}

2、Allowed Scopes

这里的Scopes将从当前 token 中的 claims中来获取,我们的鉴权服务将依靠于它来实现 。当前路由的下游API需要某个权限时,我们需要在这里声明 。和oAuth2中的 scope意义一致。

3.3.7 路由鉴权

我们通过认证中的AllowedScopes 拿到claims之后,如果要进行权限的鉴别需要添加以下配置

"RouteClaimsRequirement": {
    "UserType": "registered"
}

当前请求上下文的token中所带的claims如果没有 name=”UserType” 并且 value=”registered” 的话将无法访问下游服务。

3.3.8 路由请求头转化

请求头转发分两种:转化之后传给下游和从下游接收转化之后传给客户端。在Ocelot的配置里面叫做Pre Downstream Request和Post Downstream Request。目前的转化只支持查找和替换。我们用到的配置主要是UpstreamHeaderTransform 和 DownstreamHeaderTransform

1、Pre Downstream Request

"Test": "http://www.bbc.co.uk/, http://ocelot.com/"

比如我们将客户端传过来的Header中的 Test 值改为 http://ocelot.com/之后再传给下游

 "UpstreamHeaderTransform": {
    "Test": "http://www.bbc.co.uk/, http://ocelot.com/"
},

2、Post Downstream Request

而我们同样可以将下游Header中的Test再转为 http://www.bbc.co.uk/之后再转给客户端。

"DownstreamHeaderTransform": {
    "Test": "http://www.bbc.co.uk/, http://ocelot.com/"
},

3.3.9 全局配置

1. {`
2. `  "Routes": [],`
3. `  "Aggregates": [],`
4. `  "GlobalConfiguration": {`
5. `    "RequestIdKey": null,`
6. `    "ServiceDiscoveryProvider": {`
7. `      "Host": "192.168.80.100", // Consul Service IP`
8. `      "Port": 8500 // Consul Service Port`
9. `    },`
10. `    "RateLimitOptions": {`
11. `      "DisableRateLimitHeaders": false, // Http头  X-Rate-Limit 和 Retry-After 是否禁用`
12. `      "QuotaExceededMessage": "你的访问过于频繁请稍后在试", // 当请求过载被截断时返回的消息`
13. `      "HttpStatusCode": 253, // 当请求过载被截断时返回的http status`
14. `      "ClientIdHeader": "client_id" // 用来识别客户端的请求头,默认是 ClientId`
15. `    },`
16. `    "QoSOptions": {`
17. `      "ExceptionsAllowedBeforeBreaking": 3,`
18. `      "DurationOfBreak": 5000,`
19. `      "TimeoutValue": 5000`
20. `    },`
21. `    "BaseUrl": null,`
22. `    "LoadBalancerOptions": {`
23. `      "Type": "LeastConnection",`
24. `      "Key": null,`
25. `      "Expiry": 0`
26. `    },`
27. `    "DownstreamScheme": "http",`
28. `    "HttpHandlerOptions": {`
29. `      "AllowAutoRedirect": false,`
30. `      "UseCookieContainer": false,`
31. `      "UseTracing": false`
32. `    }`
33. `  }`
34. `}`

3.3.10 万能模板

{
      ``"DownstreamPathTemplate": "/{url}",
      ``"DownstreamScheme": "http",
      ``"DownstreamHostAndPorts": [
        ``{
          ``"Host": "localhost",
          ``"Port": 5002
        ``}
      ``],
      ``"UpstreamPathTemplate": "/{url}",
      ``"UpstreamHttpMethod": [ "Get" ]
}

3.3.11 动态路由

   {
 "Routes": [],
 "Aggregates": [],
 "GlobalConfiguration": {
   "ServiceDiscoveryProvider": {
     "Host": "localhost",
     "Port": 8500,
     "Type": "Consul",
     "Token": null,
     "ConfigurationKey": null
   },
   "LoadBalancerOptions": {
     "Type": "LeastConnection",
     "Key": null,
     "Expiry": 0
   },
   "DownstreamScheme": "https"
 }
   }
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。