Ocelot(二)- 请求聚合与负载均衡

在上一篇Ocelot的文章中,我已经给大家介绍了何为Ocelot以及如何简单使用它的路由功能,如果你还没有不了解Ocelot为何物,可以查看我的系列文章 Ocelot - .Net Core开源网关。在这篇文章中,我将会继续给大家介绍Ocelot的功能:请求聚合与负载均衡。

开篇题外话:在上一篇文章的案例中,我直接使用API返回服务器的端口和接口的路径,我感觉这样举例过于偏技术化,比较沉闷,然后我想到了之前参加PMP课程培训时候,我们的培训讲师——孙志斌老师引用小王和老李的模型给我们讲述项目管理的各种实战,可谓是生动形象,而且所举的例子也非常贴近我们的日常工作,通俗易懂,因此,我也尝试使用类似的人物形象进行案例的讲解。首先,本文将会引入两个人物Willing和Jack。Willing是一名资深专家,工作多年,而Jack则是.NET新手。

本文中涉及案例的完整代码都可以从我的代码仓库进行下载。

仓库地址:https://gitee.com/Sevenm2/OcelotDemo

案例二 请求聚合

我们在案例一路由中已经知道,Ocelot可以定义多组路由,然后根据优先级对上游服务发出的请求进行不同的转发处理,每个路由转发都匹配唯一的一个下游服务API接口。然而,有时候,上游服务想要获得来自两个API接口返回的结果。Ocelot允许我们在配置文件中声明聚合路由Aggregates,从而实现这样的效果。
举个例子,有一天我的老板(用户)让我(上游服务)去了解清楚Willing和Jack两位同事对工作安排有什么意见(请求),当然了,我可以先跑去问Jack,然后再跑到Willing那里了解情况,可是这样我就要跑两趟,这样不划算啊,于是,我去找了他们的领导(聚合)说我老板想要了解他们两个的意见,他们领导一个电话打过去,Willing和Jack就都一起过来了,我也就很快完成了老板交代的任务。
在这个过程中,我是可以单独访问Willing或者Jack的,因此,他们是在ReRoutes中声明的两组普通的路由,而他们的领导是在Aggregates中声明的一组聚合路由。刚刚我们的举例当中,访问不同的人需要到达不同的地方,因此在声明路由时,也需要注意它们的UpstreamPathTemplate都是不一样的。
下面是具体的路由配置:

"ReRoutes": [ { "DownstreamPathTemplate": "/api/ocelot/aggrWilling", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 8001 } ], "UpstreamPathTemplate": "/ocelot/aggrWilling", "UpstreamHttpMethod": [ "Get" ], "Key": "aggr_willing", "Priority": 2 }, { "DownstreamPathTemplate": "/api/ocelot/aggrJack", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 8001 } ], "UpstreamPathTemplate": "/ocelot/aggrJack", "UpstreamHttpMethod": [ "Get" ], "Key": "aggr_jack", "Priority": 2 } ], "Aggregates": [ { "ReRouteKeys": [ "aggr_willing", "aggr_jack" ], "UpstreamPathTemplate": "/aggrLeader" } ]

大家可以注意到,在ReRoutes中声明的两组路由相比案例一不同的是,多加了一个Key属性。Aggregates跟ReRoutes是同级的,而且也是一个数组,这代表着我们可以声明多个聚合路由,而在我们声明的这一组聚合路由中的属性ReRouteKeys,它包含的元素就是我们真正需要响应的路由的Key属性值。

当然,我们的下游服务也相应添加两个API接口。

// GET api/ocelot/aggrWilling [HttpGet("aggrWilling")] public async Task<IActionResult> AggrWilling(int id) { var result = await Task.Run(() => { return $"我是Willing,还是多加工资最实际, path: {HttpContext.Request.Path}"; }); return Ok(result); } // GET api/ocelot/aggrJack [HttpGet("aggrJack")] public async Task<IActionResult> AggrJack(int id) { var result = await Task.Run(() => { return $"我是Jack,我非常珍惜现在的工作机会, path: {HttpContext.Request.Path}"; }); return Ok(result); }

下面我们一起来看看执行的结果。

我们按照案例一,先单独来问问Jack。

Ocelot_002_aggrjack

然后再看看直接通过聚合路由访问

Ocelot_003_aggrleader

可以看到,在返回结果中同时包含了Willing和Jack的结果,并且是以json串的格式返回,以路由的Key属性值作为返回json的属性。

(返回的结果好像哪里不太对,不知道你是否发现了,但暂时先不要着急,我在后面会为大家揭晓)

需要注意的是,Ocelot仅支持GET方式的请求聚合。Ocelot总是以application/json的格式返回一个聚合请求的,当下游服务是返回404状态码,在返回结果中,其对应的值则为空值,即使聚合路由中所有的下游服务都返回404状态码,聚合路由的返回结果也不会是404状态码。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpsdfw.html