写在前面

API网关是系统内部服务暴露在外部的一个访问入口,类似于代理服务器,就像一个公司的门卫承担着寻址、限制进入、安全检查、位置引导等工作,我们可以形象的用下图来表示: 外部设备需要访问内部系统服务时必须要通过我们的API Gateway,目的是为了隔离内部服务和外部访问来做统一的认证授权,限流熔断,请求聚合,负载均衡,日志记录,监控预警等 通用功能,就像是我们系统的防火墙一样,在任何外部请求访问系统时都必须经过防火墙的验证。

更多关于网关的信息请参考前面的一篇文章《API网关模式》

Ocelot是什么?

Ocelot是基于.NET Core实现的轻量级API网关,它包括的主要功能有:路由、请求聚合、服务发现、认证、授权、限流熔断、并内置了LoadBanalce以及集成了Service Fabric、 Consul、Eureka等功能,这些功能只都只需要简单的配置即可使用。目前腾讯财付通的API Gateway就是基于此做的实现(参考善友兄的这篇文章),下面是详细信息以及Ocelot如何在微软官方示例代码库 eShopContainers中的使用。

Ocelot在腾讯的使用:https://customers.microsoft.com/en-us/story/tencent-telecommunications-dotnetcore
微软官方示例:https://github.com/dotnet-architecture/eShopOnContainers

Ocelot的实现机制

简单的来说它是一堆的asp.net core middleware组成的pipeline,当它拿到请求之后会用一个request builder来构造一个HttpRequestMessage发到下游的真实服务器,等下游的服务 返回response之后再由一个middleware将它返回的HttpResponseMessage映射到HttpResponse上。

代码示例

我在Github上创建了示例代码库仅供参考,我们可以使用下面的步骤来创建示例代码:(示例代码

1.创建BookingApi: dotnet new -n BookingApi
2.创建PassengerApi: dotnet new -n PassengerApi
3.创建ApiGateway: dotnet new -n ApiGateway
4.添加BookingApi和PassengerApi的实现代码
5.在ApiGateway项目中用Nuget安装Ocelot依赖包
6.添加configuration.json的配置文件
7.配置路由响应规则
8.启动服务并通过Api网关访问服务

启动BookingApi PassengerApi这两个服务,我们可以看到他们分别提供了两个接口

此时再启动我们的Api Gateway项目,通过Gateway来访问我们这两个API

我们可以看到原本我们可以直接访问的两个API现在都可以通过Gateway来访问了,那这一切是怎么做到的呢?

当我们通过Nuget安装Ocelot的依赖之后,我们需要在项目中添加.json的配置文件,在此项目中我们配置文件命名为configuration.json,内容如下:

{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/booking",
"UpstreamPathTemplate": "/api/getbooking",
"UpstreamHttpMethod": [ "Get" ],
"ReRouteIsCaseSensitive": false,
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 8001
}
],
"Key": "booking",
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "1s",
"PeriodTimespan": 15,
"Limit": 1
}
},
{
"DownstreamPathTemplate": "/api/booking/{pnr}",
"UpstreamPathTemplate": "/api/getbooking/{pnr}",
"UpstreamHttpMethod": [ "Get" ],
"ReRouteIsCaseSensitive": false,
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 8001
}
]
},
{
"DownstreamPathTemplate": "/api/passenger",
"UpstreamPathTemplate": "/api/getpassenger",
"UpstreamHttpMethod": [ "Get" ],
"ReRouteIsCaseSensitive": false,
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 8002
}
],
"Key": "passenger"
},
{
"DownstreamPathTemplate": "/api/passenger/{id}",
"UpstreamPathTemplate": "/api/getpassenger/{id}",
"UpstreamHttpMethod": [ "Get" ],
"ReRouteIsCaseSensitive": false,
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 8002
}
]
}
],
"GlobalConfiguration": {
"BaseUrl": "https://localhost:5000"
},
"Aggregates": [
{
"ReRouteKeys": [
"booking",
"passenger"
],
"UpstreamPathTemplate": "/api/getbookingpassengerinfo"
}
]
}

API Gateway帮助我们做的事情是当有请求访问网关的时候,我们经过认证授权等一系列操作确保此次访问是被允许的之后便会转发到它实际需要请求服务上去,请求结束之后再由Gateway统一将结果返回给客户端,从模板中我们可以看到UpStreamPathTemplate实际上就是我们上游请求的地址,即网关公开给外部调用的地址(此服务名称和地址我们可以根据需要随便设置更多的是为了对外界隐藏我们真实的服务地址),而实际的调用地址便是DownStreamPathTemplate中给定的实际地址。为了方便大家理解此配置的含义,我查阅了官方资料,将我们上面用到的配置文件做了注解:(更齐全的参数请参考官方文档

{
"ReRoutes": [ //路由是API网关最基本也是最核心的功能、ReRoutes下就是由多个路由节点组成。
{
"DownstreamPathTemplate": "", //下游服务模板
"UpstreamPathTemplate": "", //上游服务模板
"UpstreamHttpMethod": [ "Get" ],//上游方法类型Get,Post,Put
"AddHeadersToRequest": {},//需要在转发过程中添加到Header的内容
"FileCacheOptions": { //可以对下游请求结果进行缓存,主要依赖于CacheManager实现
"TtlSeconds": 10,
"Region": ""
},
"ReRouteIsCaseSensitive": false,//重写路由是否区分大小写
"ServiceName": "",//服务名称
"DownstreamScheme": "http",//下游服务schema:http, https
"DownstreamHostAndPorts": [ //下游服务端口号和地址
{
"Host": "localhost",
"Port": 8001
}
],
"RateLimitOptions": { //限流设置
"ClientWhitelist": [], //客户端白名单
"EnableRateLimiting": true,//是否启用限流设置
"Period": "1s", //每次请求时间间隔
"PeriodTimespan": 15,//恢复的时间间隔
"Limit": 1 //请求数量
},
"QoSOptions": { //服务质量与熔断,熔断的意思是停止将请求转发到下游服务。当下游服务已经出现故障的时候再请求也是无功而返,
并且增加下游服务器和API网关的负担,这个功能是用的Polly来实现的,我们只需要为路由做一些简单配置即可
"ExceptionsAllowedBeforeBreaking": 0, //允许多少个异常请求
"DurationOfBreak": 0, //熔断的时间,单位为秒
"TimeoutValue": 0 //如果下游请求的处理时间超过多少则自如将请求设置为超时
}
}
],
"UseServiceDiscovery": false,//是否启用服务发现
"Aggregates": [ //请求聚合
{
"ReRouteKeys": [ //设置需要聚合的路由key
"booking",
"passenger"
],
"UpstreamPathTemplate": "/api/getbookingpassengerinfo" //暴露给外部的聚合请求路径
},
"GlobalConfiguration": { //全局配置节点
"BaseUrl": "https://localhost:5000" //网关基地址
}
}

示例代码中我们在Aggregates节点下配置了路由聚合,它将两个请求的结果combine到一起再返回给客户端,当我们请求/api/getbookingpassengerinfo 时就会返回下面结果:

需要注意的是:

  1. 聚合服务目前只支持返回json
  2. 目前只支持Get方式请求下游服务
  3. 任何下游的response header并会被丢弃
  4. 如果下游服务返回404,聚合服务只是这个key的value为空,它不会返回404

有木有觉得这里的聚合很类似于GraphQL的功能,但实际上在Ocelot中并不打算实现GraphQL的功能,因为毕竟Ocelot的主要职责是实现网关的功能,聚合只是其中的一个feature,GraphQL提供了一个库 graphql-dotnet ,我们可以用它来完成需要的功能,而在Ocelot中实现类似认证,授权等这样它擅长的事情:

{
"ReRoutes": [
{
"DownstreamPathTemplate": "/graphql",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "yourgraphqlhost.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/graphql",
"DelegatingHandlers": [
"GraphQlDelegatingHandler"
]
}
]
}

官方也给出了示例:https://github.com/ThreeMammals/Ocelot/tree/develop/samples/OcelotGraphQL

此框架包含的内容比较多,在此并不一一解释,下面将谈谈其他的几个功能:

请求限流

大家注意到我们在上面例子中通过RateLimitOptions节点配置了限流的相关设置,目前我们配置的是1s钟之内只允许对booking api访问一次,否则的话便停止继续转发至下游服务,我们通过测试就会发现当在1s内多次访问的时候,网关便会返回下面的信息:

负载均衡

当我们路由到的下游服务有多个结点的时候,我们可以在DownstreamHostAndPorts中进行配置负载

{
"DownstreamPathTemplate": "/api/posts/{postId}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "10.127.1.10",
"Port": 5001,
},
{
"Host": "10.127.1.11",
"Port": 5002,
}
],
"UpstreamPathTemplate": "/posts/{postId}",
"LoadBalancer": "LeastConnection",
"UpstreamHttpMethod": [ "Put", "Delete" ]
}

LoadBalancer将决定负载均衡的算法,目前支持下面三种方式

  1. LeastConnection – 将请求发往最空闲的那个服务器
  2. RoundRobin – 轮流发送
  3. NoLoadBalance – 总是发往第一个请求或者是服务发现

Prioirty优先级

当我们配置多个请求产生冲突的时候,通过路由设置访问优化级

{
"UpstreamPathTemplate": "/goods/{catchAll}"
"Priority": 0
}
{
"UpstreamPathTemplate": "/goods/delete"
"Priority": 1
}  

万能模板

如果不希望对请求做任何的处理,则可以使用下面的万能模板:(万能模板的优先级最低,只要有其它的路由模板,其它的路由模板则会优先生效)

{
"DownstreamPathTemplate": "/{url}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 80,
}
],
"UpstreamPathTemplate": "/{url}",
"UpstreamHttpMethod": [ "Get" ]
}

本篇内容就先介绍到这里,后面将会继续探究Ocelot的内部实现。个人感觉现在.NET Core的生态越来越好,越来越多的开发人员开始尝试.NET Core并创建了很多优秀的开源项目,从微软这几年的开源策略我们更多的感受到了微软对于拥抱开源的决心,这也更加的让我们有信心在Core平台上去构建越来越多的优秀项目。如果你对技术有热情可以扫码加入我们的微信群一起探讨。

参考资料:

http://ocelot.readthedocs.io/en/latest/index.html
https://www.cnblogs.com/shanyou/p/7787183.html

Polly:
https://github.com/App-vNext/Polly

Consul:
https://github.com/hashicorp/consul

https://github.com/dotnet/home

Microsoft Blog:
https://blogs.msdn.microsoft.com/cesardelatorre/2018/05/15/designing-and-implementing-api-gateways-with-ocelot-in-a-microservices-and-container-based-architecture/

Ocelot-基于.NET Core的开源网关实现的更多相关文章

  1. Ocelot——初识基于.Net Core的API网关

    前言 前不久看到一篇<.NET Core 在腾讯财付通的企业级应用开发实践>,给现在研究.Net Core及想往微服务方向发展的人来了一剂强心针.于是我也就立刻去下Ocelot的源码及去阅 ...

  2. YiShaAdmin,基于.NET Core Web开源的后台快速开发框架

    YiShaAdmin YiShaAdmin 基于.NET Core Web开发,借鉴了很多开源项目的优点,让你开发Web管理系统和移动端Api更简单,所以我也把她开源了. 她可以用于所有的Web应用程 ...

  3. Ocelot - .Net Core开源网关

    Ocelot - .Net Core开源网关 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10857688.html 源码地 ...

  4. Ocelot(一)- .Net Core开源网关

    Ocelot - .Net Core开源网关 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10857688.html 源码地 ...

  5. .Net Core微服务——网关(1):ocelot集成及介绍

    网关是什么 简单来说,网关就是暴露给外部的请求入口.就和门卫一样,外面的人想要进来,必须要经过门卫.当然,网关并不一定是必须的,后端服务通过http也可以很好的向客户端提供服务.但是对于业务复杂.规模 ...

  6. 基于.NET CORE微服务框架 -谈谈surging API网关

    1.前言 对于最近surging更新的API 网关大家也有所关注,也收到了不少反馈提出是否能介绍下Api网关,那么我们将在此篇文章中剥析下surging的Api 网关 开源地址:https://git ...

  7. 一个技术汪的开源梦 —— 基于 .Net Core 的公共组件之 Http 请求客户端

    一个技术汪的开源梦 —— 目录 想必大家在项目开发的时候应该都在程序中调用过自己内部的接口或者使用过第三方提供的接口,咱今天不讨论 REST ,最常用的请求应该就是 GET 和 POST 了,那下面开 ...

  8. 基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)

    一.前言 至今为止编程开发已经11个年头,从 VB6.0,ASP时代到ASP.NET再到MVC, 从中见证了.NET技术发展,从无畏无知的懵懂少年,到现在的中年大叔,从中的酸甜苦辣也只有本人自知.随着 ...

  9. 《基于.NET Core构建微服务》系列文章(更新至第6篇,最新第7篇,已发布主页候选区)

    原文:Building Microservices On .NET Core – Part 1 The Plan 时间:2019年1月14日 作者:Wojciech Suwała, Head Arch ...

随机推荐

  1. java基本数据类型传递与引用传递区别

    文章转载自  zejian的博客http://blog.csdn.net/javazejian/article/details/51192130 java的值传递和引用传递在面试中一般都会都被涉及到, ...

  2. 一步一步理解 python web 框架,才不会从入门到放弃 -- 简单登录页面

    上一节,我们基本了解了 Django 的一些配置,这一节,我们将通过一个简单的登录页面,进一步学习 Django 的使用. 新建项目 首先,新建一个 Django 项目,记得别弄错了哦. settin ...

  3. 从壹开始 [Admin] 之四 || NetCore + SignalR 实现日志消息推送

    缘起 哈喽大家周一好呀,感觉好久没有写文章了,上周出差了一次,感觉还是比坐办公室好的多,平时在读一本书<时生>,感兴趣的可以看看

  4. 树莓派3b+_32位linux系统arm架构安装JDK

    如图我的Raspbian系统如下图版本信息: 可以看到是armv7l,我查了一下是32位的arm架构,即下载第一个就好了 然后用SSH Secure Shell远程上去把压缩包或者解压后的文件传过去 ...

  5. Python全国二级等级考试(2019)

    一.前言 2018年9月随着全国计算机等级考试科目中加入“二级Python”,也确立了Python在国内的地位,猪哥相信Python语言势必会像PS那般普及.不久的将来,谁会Python谁就能获得女神 ...

  6. Vue 进阶之路(二)

    之前的文章我们初识了 vue,对其原理,数据绑定和方法进行了简单的演示,本篇将对 vue 插值表达式,v-text,v-html 进行讲解. <!DOCTYPE html> <htm ...

  7. 【重学计算机】操作系统D5章:文件系统

    1. 文件系统 文件系统概述 文件的组织: 逻辑结构:流式.记录式 物理结构:顺序.连接.直接.索引 文件的存取:顺序.直接.索引 文件的控制:逻辑控制.物理控制 文件的使用:打开.关闭.读.写.控制 ...

  8. 8天入门docker系列 —— 第二天 通过一个aspnetcore程序加深对容器的理解

    我们知道容器是一个打包了应用和相关依赖的盒子,那怎么去操控这个盒子呢? 这一篇我通过一个简单的aspnetcore程序来加深对盒子的理解,使用之前先 安装一下Docker的环境. 一:Docker的安 ...

  9. 小程序 wepy框架 + iview-weapp的用法

    最近在弄wepy的时候在想有没有什么ui比较合适一点的wepy的,也是在网上看了好久发现iview还不错.引用简单,上手超快,组件绚丽!当然,这里还介绍下微信官方建议的框架也是和不错的,有需要的可以看 ...

  10. SQL Server死锁中的会话隔离级别为序列化(Serializable)实验测试

    最近在分析SQL Server的死锁时,发现一个比较有意思的现象,发现死锁当中一个会话的隔离级别为序列化(Serializable),这个是让人比较奇怪的地方,我们知道SQL Server数据库的默认 ...