第五节:基于Ocelot网关简介、路由功能、集成Consul使用
一. 基础说明
1. API网关剖析
(1).什么是Api
API是Application Programming Interface缩写,翻译成中文就是应用程序接口。在实际微服务中可以理解一个个功能方法。就比如你一个商品服务的微服务, 可以对外提供 API 接口为,获取商品目录、获取商品详情等。
(2).什么是网关(Gateway)
它是一个服务器,用来转发其他服务器通信数据的, 它接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。
(3).什么是Api网关
通俗的来说就是用来限制客户端访问服务端api一道门槛。
2. 微服务架构中为什么要用网关?
(1).在这之前,我们的技术栈中只引入了Consul,客户端访问Consul拿到对应的IP+Port,最终还是要访问业务服务器的,但很多情况我们并不想让业务服务器直接对外开放,所以这个时候就需要引入网关进行转发了.
(2).现在的微服务还没有加权限校验,如果将权限校验加个每个微服务的业务服务器上,开发量很大,这个时候引入网关,可以在网关层校验.
(3).没有网关,很难做限流,而且各个业务的负责人员不能独立负责自己的服务器器。
3. 网关都有哪些作用?
路由、负载均衡、限流、认证、授权、链路监控、熔断降级、Service Fabric
4. Ocelot相关信息
(1).依赖程序集:通过Nuget安装 【Ocelot 16.0.1】
GitHub地址:https://github.com/ThreeMammals/Ocelot
(2).参考文档:
官网:https://ocelot.readthedocs.io/en/latest/
ocelot 中文文档:https://blog.csdn.net/sD7O95O/article/details/79623654
资料:http://www.csharpkit.com/apigateway.html
(3).其他网关框架:
A. Netflix Zuul +java实现
B. Kong nginx +lua脚本实现
C. Tyk go语言开发,收费版本
D. Ocelot aspnetcore开发的
5. Ocelot的原理
Ocelot是一堆的asp.net core middleware组成的一个管道。当它拿到请求之后会用一个request builder来构造一个HttpRequestMessage发到下游的真实服务器,等下游的服务返回response之后再由一个middleware将它返回的HttpResponseMessage映射到HttpResponse上。
(1).上游是什么:Ocelot自身就是上游(Upstream)
(2).下游是什么:Ocelot转发给的(业务)服务器就是下游(Downstream)
二. 路由功能
架构图:
1.路由的含义
Ocelot(即上游)按照匹配规则接收客户端发送的请求 → 将客户端请求转换成业务服务器(即下游)的地址 → 调用下游服务,返回结果 → Ocelot再将下游服务的结果返回给客户端.
2. 参数介绍
- Downstream 下游服务配置
- UpStream 上游服务配置
- Aggregates 服务聚合配置
- ServiceName, LoadBalancer, UseServiceDiscovery 配置服务发现
- AuthenticationOptions 配置服务认证
- RouteClaimsRequirement 配置Claims鉴权
- RateLimitOptions 限流配置
- FileCacheOptions 缓存配置
- QosOptions 服务质量与熔断
- DownstreamHeaderTransform 头信息转发
3. 路由直接转发指定的地址
(1).业务场景:
客户端访问网关 → 网关把请求直接转发给"指定ip+端口"业务服务器 (该场景网关本身不配置Consul,直接转发)
(2).业务编写与测试:
A. 新建网关项目OcelotGateWay,通过Nuget安装【Ocelot 16.0.1】程序集
B. 新建一个OcelotConfig.json的配置文件,属性改为"始终复制",用于存放Ocelot的配置。
代码如下:
{
"Routes": [
{
//转发下游(业务服务器)的匹配规则
"DownstreamPathTemplate": "/api/{url}",
//下游请求类型
"DownstreamScheme": "http",
//下游的ip和端口,和上面的DownstreamPathTemplate匹配起来
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 7001
}
],
//上游(即Ocelot)接收规则
"UpstreamPathTemplate": "/GoodsService/{url}",
//上游接收请求类型
"UpstreamHttpMethod": [ "Get", "Post" ]
},
{
"DownstreamPathTemplate": "/api/{url}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 7004
}
],
"UpstreamPathTemplate": "/OrderService/{url}",
"UpstreamHttpMethod": [ "Get", "Post" ]
}
]
}
剖析上述xml:
- DownstreamPathTemplate:下游路径模板
- DownstreamScheme:下游服务http schema
- DownstreamHostAndPorts:下游服务的地址,如果使用LoadBalancer的话这里可以填多项
- UpstreamPathTemplate: 上游也就是用户输入的请求Url模板,会将这个请求转发给下游,如上代码,客户端请求 :网关ip+端口/GoodsService/{url},会转发给下游:127.0.0.1:7001/api/{url}
- UpstreamHttpMethod: 上游请求http方法,可使用数组
C. 在Program中通过AddJsonFile将上述json文件加载进来.
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) //配置相关 .ConfigureAppConfiguration((hostingContext, config) => { //1. 加载json文件 (配置后面两个参数为true,当配置文件发生变化的时候,会自动更新加载,而不必重启整个项目) config.AddJsonFile("OcelotConfig.json", optional: true, reloadOnChange: true); }) .ConfigureWebHostDefaults(webBuilder => { //添加命令行支持(写在上面的Main里也可以) var config = new ConfigurationBuilder().AddCommandLine(args).Build(); webBuilder.UseStartup<Startup>(); });
D. 在Startup中进行注册和使用,services.AddOcelot(); app.UseOcelot().Wait();
public void ConfigureServices(IServiceCollection services) { //1.注册Ocelot var ocelot = services.AddOcelot(); services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //1.使用Ocelot app.UseOcelot().Wait(); //这里不写异步用法了 app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
E. 启动项目,7001端口启动GoodsService、7004端口启动OrderService、7020端口启动OcelotGateWay,指令如下:
【dotnet GoodsService.dll --urls="http://*:7001" --ip="127.0.0.1" --port=7001】 业务服务器地址
【dotnet OrderService.dll --urls="http://*:7004" --ip="127.0.0.1" --port=7004】 业务服务器地址
【dotnet OcelotGateWay.dll --urls="http://*:7020" --ip="127.0.0.1" --port=7020】 网关地址
F. PostMan测试
(1). Get测试: http://127.0.0.1:7020/GoodsService/Catalog/GetGoodById1?id=123,会将请求地址转发给 http://127.0.0.1:7001/api/Catalog/GetGoodById1?id=123 ,请求成功。
(2). Post请求:http://127.0.0.1:7020/OrderService/Buy/pOrder1,会将请求地址转发给 http://127.0.0.1:7004/api/Buy/pOrder1,请求成功。
三. 集成Consul
与Consul结合实现业务服务器的负载均衡(推荐用法)
架构图:
1.业务背景
上述通过 Ocelot直接转发给指定的 ip+端口,只是为了演示,实际场景中,比如OrderService这个业务服务器,会部署在多台服务器上进行分摊请求压力,当然我可以利用Ocelot自身实现负载均衡,但不推荐,原因有二: ① Ocelot本身的负载均衡机制不完善 ② 每次增加或减少业务服务器,都需要改网关的配置文件,耦合性很强。
解决方案:Ocelot与Consul结合,客户端访问网关→网关通过ServiceName去Consul中找一个地址进行匹配访问(Ocelot提供了多种算法去Consul中找地址)
2.业务编写与测试
A. 通过Nuget安装【Ocelot 16.0.1】程序集 和 【Ocelot.Provider.Consul 16.0.1】程序集
B. 新建一个OcelotConfig.json的配置文件,属性改为"始终复制",用于存放Ocelot的配置.
配置分享:
//模式三:将Ocelot与consul结合处理,在consul中已经注册业务服务器地址,在Ocelot端不需要再注册了(推荐用法) { "Routes": [ { "DownstreamPathTemplate": "/api/{url}", "DownstreamScheme": "http", "ServiceName": "GoodsService", //Consul中的服务名称 "LoadBalancerOptions": { "Type": "RoundRobin" //轮询算法:依次调用在consul中注册的服务器 }, "UseServiceDiscovery": true, //启用服务发现(可以省略,因为会默认赋值) "UpstreamPathTemplate": "/GoodsService/{url}", "UpstreamHttpMethod": [ "Get", "Post" ] }, { "DownstreamPathTemplate": "/api/{url}", "DownstreamScheme": "http", "ServiceName": "OrderService", "LoadBalancerOptions": { "Type": "LeastConnection" //最小连接数算法 }, "UseServiceDiscovery": true, "UpstreamPathTemplate": "/OrderService/{url}", "UpstreamHttpMethod": [ "Get", "Post" ] } ], //下面是配置Consul的地址和端口 "GlobalConfiguration": { //对应Consul的ip和Port(可以省略,因为会默认赋值) "ServiceDiscoveryProvider": { "Host": "127.0.0.1", "Port": 8500 } } }
剖析配置:
LoadBalancer将决定负载均衡的算法
- LeastConnection – 将请求发往最空闲的那个服务器
- RoundRobin – 轮流发送
- NoLoadBalance – 总是发往第一个请求或者是服务发现
ServiceName(对应服务名), UseServiceDiscovery 启用注册发现(可省略),ServiceDiscoveryProvider 配置Consul的ip和端口。
C. 在Program中通过AddJsonFile将上述json文件加载进来. (代码同上)
D. 在Startup中进行注册和使用,services.AddOcelot().AddConsul(); app.UseOcelot().Wait();
代码分享:
public void ConfigureServices(IServiceCollection services) { //1.注册Ocelot和Consul services.AddOcelot().AddConsul(); services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //1.使用Ocelot app.UseOcelot().Wait(); //这里不写异步用法了 app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
E. 启动项目
7001,7002,7003 端口启动GoodsService、7004,7005,7006端口启动OrderService、7020端口启动OcelotGateWay
【dotnet GoodsService.dll --urls="http://*:7001" --ip="127.0.0.1" --port=7001】 业务服务器1地址
【dotnet GoodsService.dll --urls="http://*:7002" --ip="127.0.0.1" --port=7002】 业务服务器1地址
【dotnet GoodsService.dll --urls="http://*:7003" --ip="127.0.0.1" --port=7003】 业务服务器1地址
【dotnet OrderService.dll --urls="http://*:7004" --ip="127.0.0.1" --port=7004】 业务服务器2地址
【dotnet OrderService.dll --urls="http://*:7005" --ip="127.0.0.1" --port=7005】 业务服务器2地址
【dotnet OrderService.dll --urls="http://*:70046" --ip="127.0.0.1" --port=7006】 业务服务器2地址
【dotnet OcelotGateWay.dll --urls="http://*:7020" --ip="127.0.0.1" --port=7020】 网关地址
F. PostMan测试:
(1).Get测试: http://127.0.0.1:7020/GoodsService/Catalog/GetGoodById1?id=123, 会按照轮询算法依次转发给 :http://127.0.0.1:7001/api/Catalog/GetGoodById1?id=123,http://127.0.0.1:7002/api/Catalog/GetGoodById1?id=123,http://127.0.0.1:7003/api/Catalog/GetGoodById1?id=123,请求成功。
(2).Post请求:http://127.0.0.1:7020/OrderService/Buy/pOrder1 ,会根据最小连接数算法,转发给7004 7005 7006连接数最小的业务服务器。
测试结果同上述路由转发的图
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。