上一次我们通过一张架构图(.Net Core with 微服务 - 架构图)来讲述了微服务的结构,分层等内容。从现在开始我们开始慢慢搭建一个最简单的微服务架构。这次我们先用几个简单的 web api 项目以及 ocelot 网关项目来演示下网关是如何配置,如何工作的。

Ocelot 网关

Ocelot 是使用 asp.net core 开发的一个 api 网关项目。它功能丰富,集成了路由、限流、缓存、聚合等功能。它使用 .net 编写,本质上就是一堆 asp.net core 的中间件,所以它天生对 .net 友好。这些中间件拦截外部的请求,根据路由配置转发到对应的内部服务上,再把内部的返回结果对外暴露。

搭建项目结构



新建一个解决方案,新建几个项目。

  • api_gateway API网关
  • hotel_base 酒店基本信息服务
  • member_center 会员中心服务
  • ordering 订单服务

安装 Ocelot

在API网关项目上使用nuget安装Ocelot的类库。Ocelot本质上就是一堆 asp.net Core 的 middleware。所以我们需要在UseOcelot扩展方法在注册这些中间件。

Install-Package Ocelot
        public static void Main(string[] args)
{
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddJsonFile("routes.json")
.AddEnvironmentVariables();
})
.ConfigureServices(s => {
s.AddOcelot();
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConsole();
})
.UseIISIntegration()
.Configure(app =>
{
app.UseOcelot().Wait();
})
.Build()
.Run();
} }

在 main 函数内注册Ocelot的中间件,服务,使用AddJsonFile指定路由的配置文件。

路由

Ocelot最基本的功能就是反向代理。代理的配置通过一个json文件来配置。下面让我们来简单的演示下如何配置。

以下是通过网关代理访问酒店服务的酒店列表的配置示例。

 {
//获取酒店列表
"UpstreamPathTemplate": "/api/hotel",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamPathTemplate": "/hotel",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
//hotel service
"Host": "localhost",
"Port": 6003
}
]
}

配置主要是分为Upstream跟Downstream两部分。Upstream其实就是指代ocelot网关本身。Downstream代表真正的服务。

  • UpstreamPathTemplate 网关匹配的路径
  • UpstreamHttpMethod 网关匹配的请求方法
  • DownstreamPathTemplate 服务匹配的路径
  • DownstreamScheme 服务的Scheme,http、https
  • DownstreamHostAndPorts 服务的主机地址跟端口

上面的配置描述的意思是:把对网关的/api/hotel的GET请求转发到主机http://localhost:6003/hotel接口上。

路由参数

Ocelot的path模板可以使用{param}模式来匹配参数,然后传递到下游服务器上。

    {
//获取单个酒店
"UpstreamPathTemplate": "/api/hotel/{hotel_id}",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamPathTemplate": "/hotel/{hotel_id}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
//hotel service
"Host": "localhost",
"Port": 6003
}
],
"Key": "hotel_base_info",
}

使用{hotel_id}匹配hotelId参数。

    {
//获取酒店房间列表
"UpstreamPathTemplate": "/api/hotel_rooms/{hotel_id}",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamPathTemplate": "/room/hotel_rooms/{hotel_id}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
//hotel service
"Host": "localhost",
"Port": 6003
}
],
"Key": "hotel_rooms"
}

使用{hotel_id}匹配hotelId参数。

    {
//获取查询订单
"UpstreamPathTemplate": "/api/order/query?day={day}",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamPathTemplate": "/order/get_orders?day={day}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
//order service
"Host": "localhost",
"Port": 6001
}
]
}

在QueryString上使用{day}匹配参数。

限流

Ocelot支持对请求的限流操作。

 "RateLimitOptions": {
"EnableRateLimiting": true,
"Period": "1s",
"PeriodTimespan": 1,
"Limit": 1
}

在路由配置节点添加RateLimitOptions节点。

  • EnableRateLimiting = true 开启限流
  • Period = 1s 限流的时间区间为1s
  • PeriodTimespan = 1 限流后重置时间
  • Limit = 1 限制请求的数量

上面的配置的意思是1秒内限制一次请求,1秒后重置这个限制。

缓存

Ocelot可以对请求的响应值提供缓存服务。

//缓存5s
"FileCacheOptions": { "TtlSeconds": 5 }

在路由配置节点上配置FileCacheOptions字段,TtlSeconds代表需要缓存的时间,单位是秒。

聚合

上一回我们讲微服务架构的时候说到“聚合服务层”,我们说这一层的主要功能是对请求进行聚合适配跟裁剪。其实ocelot已经提供了简单的api聚合功能。如果聚合的需求比较简单,那么可以使用ocelot直接实现。

简单聚合

简单聚合可以通过配置把几个请求的聚合成一个请求,一次性返回几个请求的响应。响应通过json格式被包装返回。

  "Aggregates": [
{
//聚合 查询酒店信息跟酒店房间列表
"RouteKeys": [
"hotel_base_info",
"hotel_rooms"
],
"UpstreamPathTemplate": "/api/hotel_detail/{hotel_id}"
},
]

RouteKeys 代表需要聚合的请求的键值。

使用代码聚合

上面我们直接通过配置实现了api之间聚合请求。这种聚合比较简单,会把聚合的几个请求的响应值原封不动的返回回来。有的时候我们需要对返回值做一些转换或者裁剪,比如同一个api我们对移动端的响应可能需要裁剪掉部分字段。这种需求在ocelot内我们可以使用代码来完成。

其实我们完全可以在代码里写业务,但是这种操作是绝对不推荐的。

这里我们演示下如何把获取酒店信息跟酒店房间列表的返回值进行裁剪,并返回一个新的响应。

    public class HotelDetailInfoForMobileAggregator : IDefinedAggregator
{
public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses)
{
dynamic hotelInfo = new ExpandoObject();
List<dynamic> rooms = new List<dynamic>();
foreach (var context in responses)
{
if ((context.Items["DownstreamRoute"] as dynamic).Key == "hotel_base_info")
{
var respContent = await context.Items.DownstreamResponse().Content.ReadAsStringAsync();
hotelInfo = JsonConvert.DeserializeObject<dynamic>(respContent);
}
if ((context.Items["DownstreamRoute"] as dynamic).Key == "hotel_rooms")
{
var respContent = await context.Items.DownstreamResponse().Content.ReadAsStringAsync();
rooms = JsonConvert.DeserializeObject<List<dynamic>>(respContent);
}
} dynamic newResponse = new ExpandoObject();
newResponse.hotel = new {
hotelInfo.id,
hotelInfo.name
};
newResponse.rooms = rooms.Select(x => new {
x.id,
x.no
}); var stringContent = new StringContent(JsonConvert.SerializeObject(newResponse)); return new DownstreamResponse(
stringContent,
System.Net.HttpStatusCode.OK,
responses.SelectMany(x => x.Items.DownstreamResponse().Headers).ToList(),
"OK");
}
}

每一个聚合都需要继承IDefinedAggregator这个接口然后实现Aggregate方法。在这个方法内对每个请求的响应值进行裁剪,然后重新组合。

    {
//聚合 查询酒店信息跟酒店房间列表 移动端 裁剪
"RouteKeys": [
"hotel_base_info",
"hotel_rooms"
],
"UpstreamPathTemplate": "/api/m/hotel_detail/{hotel_id}",
"Aggregator": "HotelDetailInfoForMobileAggregator"
}

在配置文件的Aggregates内添加一个配置节点在“Aggregator”字段上指定Aggregator的类名。

  .ConfigureServices(s => {
s.AddOcelot()
.AddTransientDefinedAggregator<HotelDetailInfoForMobileAggregator>();
})

同时在ConfigureServices方法内配置HotelDetailInfoForMobileAggregator的依赖注入。

总结

本次我们通过几个最简单的web api项目,演示了如何使用 ocelot 网关进行反向代理,限流,聚合等常用功能。可以看到 ocelot 的配置使用还是比较简单的。因为是 .net 代码编写,所以对.net 开发者比较友好,我们可以直接使用 .net 代码来编写一些功能,比如直接使用代码来聚合请求的结果。

相关文章

NET Core with 微服务 - 什么是微服务

.Net Core with 微服务 - 架构图

演示代码

https://github.com/kklldog/myhotel_microservice

关注我的公众号一起玩转技术

.Net Core with 微服务 - Ocelot 网关的更多相关文章

  1. c# 微服务Ocelot网关服务发现

    前面提到微服务方案,介绍了该东西,推荐一篇介绍博文https://www.cnblogs.com/jesse2013/p/net-core-apigateway-ocelot-docs.html 我要 ...

  2. .Net Core with 微服务 - Consul 注册中心

    上一次我们介绍了 Ocelot 网关的基本用法.这次我们开始介绍服务注册发现组件 Consul 的简单使用方法. 服务注册发现 首先先让我们回顾下服务注册发现的概念. 在实施微服务之后,我们的调用都变 ...

  3. .Net Core with 微服务 - Seq 日志聚合

    上一次我们介绍并演示了如果使用 Consul 做为我们微服务的注册中心,来实现服务的注册与发现.那么本次我们讲会演示如何做日志聚合.日志聚合比较常用的有 ELK 等,但是这次我想要介绍的是一款比较小众 ...

  4. .Net Core with 微服务 - Elastic APM

    上一次我们介绍了Seq日志聚合组件.这次要给大家介绍的是Elastic APM ,一款应用程序性能监控组件.APM 监控围绕对应用.服务.容器的健康监控,对接口的调用链.性能进行监控.在我们实施微服务 ...

  5. .Net Core with 微服务 - Consul 配置中心

    上一次我们介绍了Elastic APM组件.这一次我们继续介绍微服务相关组件配置中心的使用方法.本来打算介绍下携程开源的重型配置中心框架 apollo 但是体系实在是太过于庞大,还是让我爱不起来.因为 ...

  6. .Net Core with 微服务 - Polly 服务降级熔断

    在我们实施微服务之后,服务间的调用变的异常频繁.多个服务之间可能是互相依赖的关系.某个服务出现故障或者是服务间的网络出现故障都会造成服务调用的失败,进而影响到某个业务服务处理失败.某一个服务调用失败轻 ...

  7. .Net Core with 微服务 - 分布式事务 - 2PC、3PC

    最近比较忙,好久没更新了.这次我们来聊一聊分布式事务. 在微服务体系下,我们的应用被分割成多个服务,每个服务都配置一个数据库.如果我们的服务划分的不够完美,那么为了完成业务会出现非常多的跨库事务.即使 ...

  8. .Net Core with 微服务 - 分布式事务 - TCC

    上一次我们讲解了分布式事务的 2PC.3PC .那么这次我们来理一下 TCC 事务.本次还是讲解 TCC 的原理跟 .NET 其实没有关系. TCC Try 准备阶段,尝试执行业务 Confirm 完 ...

  9. .Net Core with 微服务 - 分布式事务 - 可靠消息最终一致性

    前面我们讲了分布式事务的2PC.3PC , TCC 的原理.这些事务其实都在尽力的模拟数据库的事务,我们可以简单的认为他们是一个同步行的事务.特别是 2PC,3PC 他们完全利用数据库的事务能力,在一 ...

随机推荐

  1. Symmetry UVA - 1595

      The figure shown on the left is left-right symmetric as it is possible to fold the sheet of paper ...

  2. Day13_66_sleep()方法 (二)

    sleep()方法 (二) * 因为sleep()是静态方法,所以用 线程对象名.sleep() 和 Thread.sleep()是一样的意思,用线程对象名调用并不等于让线程对象名所指向的线程阻塞,而 ...

  3. IOS Widget(1):概述

    引言   本系列文章作者是安卓开发,以安卓开发的视角学习IOS小组件,记录一下踩坑记录,如有讲得不对的地方,路过大佬多包涵.如果你是想深入学习小组件,建议您顺着笔者的编号顺序阅读本系列文章.如果曾经了 ...

  4. 手动脱PeCompact 2.20壳实战

    作者:Fly2015 PeCompact壳又是一个没有听说过的壳,需要脱壳的程序是吾爱破解培训的第一课的选修作业四.最近对脱壳有点上瘾了,当然也遭受了脱壳受挫的无奈,但是比较幸运还是把这个壳给搞了. ...

  5. 对c语言回调函数的理解

    对于回调函数,可以简单的理解为一种特别的函数调用方法,我们可以对比一下回调函数与普通函数在调用方法上的区别. 1. 普通函数调用 一般为实现方在其函数体执行过程中直接调用. 代码示例: #includ ...

  6. Python中Selenium模块的使用

    目录 Selenium的介绍.配置和调用 Selenium的配置 Selenium的调用 Selenium的使用 定位 定位元素的使用 定位下拉标签元素 在iframe框架之间切换 上传文件 Webd ...

  7. NetBIOS名称欺骗和LLMNR欺骗

    目录 LLMNR和NetBios 攻击原理 Responder 攻击过程 LLMNR和NetBios 什么是LLMNR和NetBIOS名称服务器广播? 当DNS名称服务器请求失败时,Microsoft ...

  8. Django中的表单

    目录 表单 Django中的表单 用表单验证数据 自定义验证 表单 HTML中的表单是用来提交数据给服务器的,不管后台服务器用的是 Django  还是 PHP还是JSP还是其他语言.只要把 inpu ...

  9. 学习Canvas绘图与动画基础 制作弧和圆(五)

    1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="U ...

  10. 前端不得不了解的TCP协议

    背景 早期的网络是基于OSI(开放式系统互联网,一般叫OSI参考模型)模型,该模型是由ISO国际标准组织制定的,包含了七层(应用层.表示层.会话层.传输层.网络层.数据链路层.物理层),即复杂又不实用 ...