上一次我们通过一张架构图(.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. java面试一日一题:讲下在什么情况下会发生类加载

    问题:请讲下在什么情况下会发生类加载? 分析:该问题主要考察对java中类加载的知识,什么是类加载,为什么会发生类加载,什么情况下发生类加载? 回答要点: 主要从以下几点去考虑 1.什么是类加载: 2 ...

  2. ORM 创新解放劳动力 -SqlSugar 新功能介绍

    介绍 SqlSugar是一款 老牌 .NET 开源ORM框架,由果糖大数据科技团队维护和更新 ,Github star数仅次于EF 和 Dapper 优点: 简单易用.功能齐全.高性能.轻量级.服务齐 ...

  3. IOS Widget(3):SwiftUI开发小组件布局入门

    引言   经过上一篇文章,我们已经可以在桌面上展示出一个小组件出来了,你肯定想小试牛刀,动手改一改,那我们就从改小组件的布局做起吧.本文不会讲解Swift语法,如果是熟悉Flutter,Kotlin这 ...

  4. ubuntu 14.04.5 编译Android 4.4.4 r1源码(最新)

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/54426189 吐槽:ubuntu系统真是让人又爱又恨,也有可能是VMware Wo ...

  5. hdu3786 Floyd或搜索 水题

    题意: 找出直系亲属 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  6. Windows XP sp3 系统安装 Windbg 符号文件 Symbols 时微软失去支持的解决方案

    0x01 前言 Windbg 是微软的正宗调试器,在正常的情况下调试一些程序并没有什么问题,但是如果需要调试分析程序的堆栈,或者是一些特殊的功能时则需要微软的符号文件的支持,所以符号文件是非常重要的, ...

  7. PowerShell-4.API调用以及DLL调用

    PowerShell可以直接调用API,So...这东西完全和cmd不是一回事了... 调用API的时候几乎和C#一样(注意堆栈平衡): 调用MessageBox: $iii = Add-Type - ...

  8. nodejs-模块系统

    Node.js模块系统 为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统. 模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的.换言之,一个 Node. ...

  9. [CTF]栅栏密码学习

    [CTF]栅栏密码学习 即把将要传递的信息中的字母交替排成上下两行,再将下面一行字母排在上面一行的后边,从而形成一段密码.栅栏密码是一种置换密码. 例如密文:TEOGSDYUTAENNHLNETAMS ...

  10. 你注意到了吗?修改API文档也需要规范!

    关于API接口文档的内容和格式规范的文章,之前也有写过,网上也有不少写的比我还好的,就不赘述了,今天想说的是一个很容易被忽略的点,修改API文档的规范:版本控制. 示例 拿Eolinker来演示一下流 ...