上篇讲了net5+consul:
.Net5+Consul服务注册发现_二后生的博客-CSDN博客
这篇主要是consul结合ocelot的实现
自己简单理解概念:
虽然consul实现了服务注册的服务与发现,当然自身也有不错的负载均衡机制与路由转发,但是针对于上下游服务的调用不是那么牛逼,他在微服务中仅做服务注册与发现工作,下面网关的作用就是弥补他缺少的这些功能。
那ocelot网关的作用就是实现了:配置实现路由、请求聚合、服务发现、认证、鉴权、限流、熔断、并内置了负载均衡器等等功能。
简单画了个图:
一、Ocelot+Consul结合:
1、新建一个网关的 .netcorewebapi的项目:
2、nuget安装
第一个主要是ocelot的类包
第二个主要是ocelot与consul相关联的类包
3、可以看到第一步截图内新建的configuration.json文件,我们用它来配置网关。
新建了之后,需要在Program.cs文件内项目启动时使用这个文件,如下(我这是net5框架):
4、startup文件内注册ocelot和consul
使用ocelot中间件
5、配置configuration.json文件内容
//*****************************Ocelot+Consul********************************
{
"Routes": [
{
"DownstreamPathTemplate": "/api/{url}", //下游服务地址--url变量
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/GateWayTest/{url}", //上游请求路径,网关地址--url变量
"UpstreamHttpMethod": [ "Get", "Post" ],
//consul
"UseServiceDiscovery": true, //使用服务发现
"ServiceName": "Cbf.Oscar.Service", //consul服务名称
"LoadBalancerOptions": {
"Type": "RoundRobin" //轮询 LeastConnection-最少连接数的服务器 NoLoadBalance不负载均衡
},
"GlobalConfiguration": {
//"BaseUrl":"http://198.12.168.55", //网关对外地址
//配置consul地址
"ServiceDiscoveryProvider": {
"Host": "127.0.0.1",
"Port": 8500,
"Type": "Consul" //由consul提供服务发现,ocelot也支持etc等
}
}
}
]
}
根据上面注释制定好自己下游的url,还有自己网关的地址,还有配置consul的地址就好了。
6、最后启动后的效果就是:
(1)我的consul列表:注册了俩实例
(2)切换到网关目录cmd启动自己的网关服务:dotnet run --urls http://localhost:2000
然后请求自己本地网关地址(网关实现了轮循负载均衡和路由转发):
http://localhost:2000/GateWayTest/Index/getDetails
二、网关加缓存(可选项,按照自己业务设计)
简单说一下:缓存能有效提升程序性能。
缓存是针对下游地址缓存的,同一个地址请求返回相同数据,例如针对一些不变的数据才能做缓存,所以根据用户登录信息不同返回不同数据的就不适合用了。
1、首先要给网关类库安装nuget包:Ocelot.Cache.CacheManager
2、然后在ConfigureServices 注册这个方法:
3、然后在配置文件配置缓存
4、测试一下
可以接口返回一个当前时间,因为上面配置的过期时间是10秒,所以刷新的时候观察这个时间,十秒钟就会过期,并返回新的数据
三、限流
为什么要限流呢,防止请求过多把程序搞宕机了,也可以有效防止爬虫和ddos攻击,预估出服务的处理能力,然后设置限流,可以限制单位时间内的访问量(失败一部分请求比整个服务挂掉强)。
实现步骤:
配置中心新增一些限流的配置:
{
"Routes": [
{
"DownstreamPathTemplate": "/api/{url}", //下游服务地址--url变量
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/GateWayTest/{url}", //上游请求路径,网关地址--url变量
"UpstreamHttpMethod": [ "Get", "Post" ],
//consul
"UseServiceDiscovery": true, //使用服务发现
"ServiceName": "Cbf.Oscar.Service", //consul服务名称
"LoadBalancerOptions": {
"Type": "RoundRobin" //轮询 LeastConnection-最少连接数的服务器 NoLoadBalance不负载均衡
},
//限流操作
"RateLimitOptions": {
"ClientWhitelist": [ "eleven", "seven" ], //设置白名单:ClientId=eleven(http请求传header,ClientId区分大小写,白名单不受限流)
"EnableRateLimiting": true, //开启,默认true
"Period": "5m", //1s, 5m, 1h, 1d
"PeriodTimespan": 30, //多少秒之后客户端可以重试
"Limit": 5 //统计时间段内允许的最大请求数量
//简述上面限流条件:5分钟之内最多请求5次,失败了(超出五次也算),30秒之后客户端才可以重新请求
}
//网关缓存,这里表示缓存10秒,10秒后过期。另外,貌似只支持get方式,只要请求的URL不变,就会缓存。
//"FileCacheOptions": {
// "TtlSeconds": 10, //second 过期时间
// "Region": "UserCache" //
//},}
],
"GlobalConfiguration": {
//"BaseUrl":"http://0.0.0.1", //网关对外地址
//配置consul地址
"ServiceDiscoveryProvider": {
"Host": "127.0.0.1",
"Port": 8500,
"Type": "Consul" //由consul提供服务发现,ocelot也支持etc等
},
//网关限流 超出限制 可以自定义返回消息
"RateLimitOptions": {
"DisableRateLimitHeaders": false, // Http头 X-Rate-Limit 和 Retry-After 是否禁用
"QuotaExceededMessage": "Fuck U,You can only ask five times in five fucking minutes!", //当请求过载被截断时返回的消息(不支持中文)
"HttpStatuCode": 666 //错误码 自定义
//"ClientIdHeader": "client_id" // 用来自定义客户端的请求头,默认是 ClientId
}
}
}
可以看到上面的配置,在以前的基础上加了:
1、routes内新加的限流配置2、注:这里把GlobalConfiguration拿到Rotes同级,这里配置是限流返回的一些信息。
3、看效果
请求网关地址返回数据了:
但是在5分钟之内我刷新了五次,第六次的时候就会超出限定数量,出现下图:
当然,ClientWhitelist 定义的白名单不限流,白名单刷新多少次都行
ok限流就到这里了
四、熔断
熔断的意思是停止将请求转发到下游服务。当下游服务已经出现故障的时候再请求也是无功而返,并且还会增加下游服务器和API网关的负担。这个功能是用的ocelot结合Pollly来实现的,我们只需要为路由做一些简单配置即可
1、nuget安装 Ocelot.Provider.Polly
Ocelot.Provider.Polly的熔断机制是一个超时和熔断的组合,(Polly有超时策略,熔断策略,这里是2个策略的结合使用),所以如果是单单是服务报500异常是触发不了的。
接口超过多长时间进入半熔断状态,返回服务不可用, 连续超过多少次进入熔断状态就直接停掉该请求返回,多长时间再恢复。
2、依赖注入polly
3、配置文件添加红框的内容:
配置就完成了
4、在service中添加一个接口用于测试
private static int _count;
/// <summary>
/// 测试熔断效果
/// </summary>
/// <returns></returns>
[HttpGet("GetQoS")]
public IEnumerable<string> GetQoS()
{
_count++;
Console.WriteLine($"Get...{_count}");
if (_count <= 3)
{
System.Threading.Thread.Sleep(5000); //因为timeout设置的是3秒,这里设置让其超时5秒触发ocelot熔断保护机制,就会返回失败,不会走下面的return
}//如果_count超出三个就说明正常,主要是测试熔断
return new string[] { $"请求成功,ClinetService: {DateTime.Now.ToString()} {Environment.MachineName} " +
$"OS: {Environment.OSVersion.VersionString}" };
}
建议起一个线程即可。然后刷新自己读秒观察
//测试结果:
//1、刷新运行三秒失败返回503 Get...1 (第1次异常)
//2、刷新运行三秒失败返回503 Get...2 (第2次异常)
//3、熔断5秒(因配置只允许两次异常,上面两次异常,则触发本次熔断机制)
//4、刷新运行三秒失败返回503 Get...3 (第二轮的第一次异常)
//5、熔断5秒 (不清楚这里为什么会熔断5秒,按理说第二轮的第二次异常还没出现,可能是最大2次异常,之后异常一次就触发会熔断吧)
//6、直接成功 Get...4
//7、直接成功 Get...5、Get...6、Get...7。。。。 后面都成功
五、降级
其实熔断和限流也算是一种降级,降级就是当我们指定的代码处理失败时就执行我们备用的代码,但是这个好像没跟ocelot相关联,需要单独使用polly包,也不用配置啥的安装即用。
实现步骤:
1、安装NuGet包 Polly (安装在各个服务类库上)
2、
startup注册这个接口类为单例模式
第一种方法:使用构造函数,实例一定要以单例模式注入,因为如果是每次都执行构造函数给_policy赋一次值,那_policy每次都是全新的,下面的熔断策畋会不生效。
然后在构造函数中注入polly
第二种方法:在接口中使用polly
上面这种是这个接口类统一使用一个降级策略,需要注入ioc。
下面这个方案不同的是一个方法一个降级策略,可以自己根据业务设计合适策略
3、那上面两种方案的Execute就是polly监控的代码块,如果polly监控到错误则Fallback进行降级策略。下面就是个测试结果。
六、Ocelot动态路由
因为我们上面的例子都是写死在Routes中的,网关只能转发Cbf.Oscar.ServiceInstance一个服务。客户端请求微服务时,不可能只请求一个服务,所以客户端的请求网关地址是不可能写死的,我们一般会通过服务名称来请求不同的服务接口,动态路由就是ocelot通过服务名称去consul找到对应的服务再返回并转发出去。
具体实现就是只改配置文件的 Routes 就行了,如下配置
图中,因为需要动态请求,所以routes不再使用,把之前的那些静态路由都拿到了全局中。
然后如果想每个服务都设置自己的限流的话可以使用DynamicRoutes(与GlobalConfiguration同级),如图:
配置完之后客户端请求网关就可以通过服务名称了,如下
既然各服务都有各自的限流,我就想到了各服务是不是也有各自的熔断、各自的限流异常信息提示、但是经过搜索和尝试,好像是没有这个功能。。。
动态路由就讲完了
总文参考资料:
Consul+Ocelot+Polly缓存、限流、熔断、降级 - 走看看
Ocelot简易教程(四)之请求聚合以及服务发现 - 依乐祝 - 博客园
还有一堆,找不到链接了。。
over