在上篇.Net微服务实践(三)[网关]:Ocelot配置路由和请求聚合中咱们介绍了Ocelot的配置,主要特性路由以及服务聚合。接下来,咱们会介绍Ocelot的限流、熔断、缓存以及负载均衡。html
咱们先来看限流的配置git
Reroute节点中的配置以下:github
{ "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ], "RateLimitOptions": { "ClientWhitelist": [], "EnableRateLimiting": true, "Period": "10m", "PeriodTimespan": 3, "Limit": 1 } }
GlobalConfiguration中的配置以下:算法
"GlobalConfiguration": { "BaseUrl": "http://localhost:5000", //限流 "RateLimitOptions": { "QuotaExceededMessage": "您的请求量超过了配额1/10分钟", "HttpStatusCode": 999 } }
配置说明json
在Reroute和GlobalConfiguration节点中添加了RateLimitOptions节点api
示例说明
客户端在10分钟以内只容许请求一次http://localhost:5000/api/orders,在请求以后3秒钟以后能够重试缓存
验证服务器
修改配置,运行示例程序,app
访问http://localhost:5000/api/orders,第一次能够正常获取返回结果,再次访时,显示"您的请求量超过了配额1/10分钟, 而且response状态码是999负载均衡
PeriodTimespan的验证
修改Period为1s, 修改PeriodTimespan为10,这样当前的配置是1秒中容许一个请求,10秒后才能重试。 再次运行示例程序。
访问http://localhost:5000/api/orders,第一次能够正常获取返回结果, 等待两秒,再次访问,你们想一下,这个时候,会不会返回正常结果(已通过了两秒)。这时仍是返回999,为何? 由于尽管配额上是容许的,可是由于配置是客户端10秒之后才能重试,而这时只等待了2秒,因此仍是返回999.
Ocelot的熔断使用了Polly来实现,在OcelotGateway项目添加Polly包
注入Polly
services .AddOcelot() .AddPolly();
修改配置
{ "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ], "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 2, "DurationOfBreak": 5000, "TimeoutValue": 2000 } }
配置说明
在Reroute节点中添加了QoSOptions节点
示例说明
当访问http://localhost:5000/api/orders出现2次异常后,服务熔断5秒,若是服务响应超过2秒,也触发熔断条件
验证
场景一:服务宕机
修改配置,只启动网关,不启动oder api,访问http://localhost:5000/api/orders,第一次有响应耗时,返回500,第二次也有响应耗时,返回500. 第三次则快速返回503 Service Unavalible, 服务熔断了。
场景二:超时
修改配置
修改api/orders代码,等待3秒
// GET: api/orders [Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { Task.Delay(3000).Wait(); return new string[] { "刘明的订单", "王天的订单" }; }
启动网关,启动order-api,访问http://localhost:5000/api/orders,返回503
// GET: api/orders [Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { throw new Exception("获取全部订单出错"); }
启动网关,启动order-api,访问http://localhost:5000/api/orders, 不触发熔断
缓存使用了CacheManageer来实现,添加CacheManager包
Install-Package Ocelot.Cache.CacheManager
注入缓存组件
services.AddOcelot() .AddCacheManager(x => { x.WithDictionaryHandle(); });
Ocelot.json配置文件修改
{ "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ], "FileCacheOptions": { "TtlSeconds": 60, "Region": "orders" } }
缓存是根据 downstream service 的URL来缓存的
配置说明
在Reroute节点中添加了FileCacheOptions节点
示例说明
当访问http://localhost:5000/api/orders后,结果会缓存60秒,在缓存有效期内即便原始的order api的返回结果发生变化,经过网关请求时,仍是会返回缓存的结果。
验证
"刘明的订单", "王天的订单"
[Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { return new string[] { "帅的订单", "个人订单" }; }
"刘明的订单", "王天的订单"
由于结果被缓存了
"帅的订单", "个人订单"
由于缓存有效期已通过了
Ocelot容许在上游服务的request和下游服务的response的header中添加、替换信息
配置以下:
{ "DownstreamPathTemplate": "/api/shopping-carts", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "DownstreamHeaderTransform": { "devops": "rdc" }, "UpstreamPathTemplate": "/api/shopping-carts", "UpstreamHttpMethod": [ "Get" ], "UpstreamHeaderTransform": { "lakin": "rdc", "CI": "msbuild, jenkins", "Location": "http://localhost:5001, {BaseUrl}" } }
配置说明
在Reroute节点中添加了DownstreamHeaderTransform节点和UpstreamHeaderTransform节点
"DownstreamHeaderTransform": { "devops": "rdc" }
说明:在下游服务的response中添加一个header, key是devops, value是rdc
"UpstreamHeaderTransform": { "lakin": "rdc", "CI": "msbuild, jenkins", "Location": "http://localhost:5001, {BaseUrl}" }
示例说明
当访问http://localhost:5000/api/orders后,结果会缓存60秒,在缓存有效期内即便原始的order api的返回结果发生变化,经过网关请求时,仍是会返回缓存的结果。
验证
// GET: api/shopping-carts [Route("api/shopping-carts")] [HttpGet] public IEnumerable<string> Get() { Console.WriteLine($"开始打印header信息"); foreach (var item in this.Request.Headers) { Console.WriteLine($"{item.Key} - {item.Value}"); } Console.WriteLine($"打印header信息完成"); return new string[] { "洗发水", "无人机" }; }
"CI": "msbuild", "Location": "http://localhost:5001"
开始打印header信息CI lakin - rdc CI - jenkins Location - http://localhost:5000 打印header信息完成
devops - rdc
Ocelot容许在路由时转化HTTP方法
{ "DownstreamPathTemplate": "/api/shopping-carts", "DownstreamScheme": "http", "DownstreamHttpMethod": "POST", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/shopping-carts", "UpstreamHttpMethod": [ "Get" ] }
示例说明
上述示例中,将GET /api/shopping-carts 路由到 POST /api/shopping-carts, 将GET转换成了POST
适用场景:例若有些已经存在的的API,由于某些历史缘由都是用POST,在经过网关对外提供服务时,就能够按照标准API进行转换
验证
"洗发水", "无人机"
[Route("api/shopping-carts")] [HttpPost] public string Post() { return "添加商品到购物车成功"; }
添加商品到购物车成功
Ocelot内置了负载均衡,咱们先来看配置
{ "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 }, { "Host": "localhost", "Port": 6001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ], "LoadBalancerOptions": { "Type": "RoundRobin" } }
配置说明
在DownstreamHostAndPorts指指定多个服务地址
在Reroute节点中添加LoadBalancerOptions,这是负载均衡的配置节点,其中Type属性指定了负载均衡的算法, 它有以下几个值:
验证
[Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { return new string[] { "刘明的订单", "王天的订单" }; }
[Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { return new string[] { "帅的订单", "个人订单" }; }
第一次的结果是
"刘明的订单", "王天的订单"
第二次的结果是
"帅的订单", "个人订单"
第三次的结果是
"刘明的订单", "王天的订单"
Ocelot自己是一组中间件,它也提供了方式来注入和重写其中的某些中间件:
下面是注入PreErrorResponderMiddleware中间件的代码示例:
//注入中间件 var configuration = new OcelotPipelineConfiguration { PreErrorResponderMiddleware = async (ctx, next) => { ctx.HttpContext.Request.Headers.Add("myreq", "ocelot-request"); await next.Invoke(); } }; app.UseOcelot(configuration).Wait();
注意: Ocelot也是一组中间件,因此能够在Ocelot中间件以前,按常规方式添加任何中间件, 可是不能在Ocelot中间件以后添加,由于Ocelot没有调用 next
Ocelot提供了一组后台管理的API, 从前三篇文章能够看出,Ocelot主要也就是配置文件的管理,因此API主要也就是管理配置
本篇咱们介绍了Ocelot的限流、熔断、缓存、负载均衡以及其余一些特性。到目前为止,Ocelot的基本配置和功能都已经介绍完了。接下里咱们会结合consul来介绍服务发现,以及Ocelot和Consul的集成。