Ocelot-基于.NET Core的开源网关实现

写在前面

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

640?wx_fmt=png

更多关于网关的信息请参考前面的一篇文章《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

640?wx_fmt=png


Ocelot的实现机制

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

640?wx_fmt=gif


代码示例

我在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这两个服务,我们可以看到他们分别提供了两个接口

640?wx_fmt=png

640?wx_fmt=png

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

640?wx_fmt=png

我们可以看到原本我们可以直接访问的两个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 时就会返回下面结果:

640?wx_fmt=png

需要注意的是:

  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内多次访问的时候,网关便会返回下面的信息:

640?wx_fmt=png

负载均衡

当我们路由到的下游服务有多个结点的时候,我们可以在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/

原文地址:https://www.cnblogs.com/xiandnc/p/9374533.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/320651.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Blazor 0.5.0 升级及新特性介绍

前言喜大普奔, Blazor 0.5.0 在我刷了好几遍 Github (表示功不可没)以后,终于在 2018年7月25日发布了![Blazor 0.5.0 Announce] (https://blogs.msdn.microsoft.com/webdev/2018/07/25/blazor-0-5-0-experimental-rele…

NuStore使用说明

简介.net core 部署有两种方式,一种是独立式部署(SCD),另一种是框架依赖式部署(FDD)。以SCD方式生成发布包时,dotnet会将所有依赖打包到一个文件夹内,并为应用程序生成可执行文件。以…

HttpClientFactory与Steeltoe结合来完成服务发现

前言上一篇说了一下用HttpClientFactory实现了简单的熔断降级。这篇就来简单说说用HttpClientFactory来实现服务发现。由于标题已经好明显的说了Steeltoe因此这里会要求有Spring Clound的相关环境,本文也默认各位对这里有些许了解,所以不会涉及搭建过程的…

业务流程、长周期服务和微服务

在近期于伦敦Skills Matter举行的DDD eXchange 2018会议上,Martin Schimak认为在最近几年间,领域事件引发了越来越多的讨论,但是我们对命令也应如此,在这次会议上他讨论了微服务领域的事件、命令以及长周期的服务,以及…

.NET Core TDD 前传: 编写易于测试的代码 -- 构建对象

该系列第1篇: 讲述了如何创造"缝". "缝"(seam)是需要知道的概念.本文是第2篇, 介绍的是如何避免在构建对象时写出不易测试的代码. 本文的概念性内容大部分都来自Misko Hevery的这篇博客文章.构建还是用上文里汽车的例子.通常情况下, 我们是先去建造汽车, …

构建可扩展的有状态服务

原文链接:http://highscalability.com/blog/2015/10/12/making-the-case-for-building-scalable-stateful-services-in-t.html在很长一段时间内,分布式系统都采用无状态服务作为分布式系统扩展的最佳实践。它可以通过简单的循环负载均衡来提供扩展能力。…

树莓派3B+,我要跑.NET CORE

前面的话我也不知道为什么,看到.net core觉得很爽,可以真正的跨平台,个人觉得很喜欢,所以就准备拿树莓派来验证我的想法。在我写这篇文章的时候,刚好在树莓派上装好了core2.1,先上结果。一、基础准备从板子…

【DP】【高精】WZK打雪仗(jzoj 1997)

WZK打雪仗 jzoj 1997 题目大意&#xff1a; 在一个环上有n*2个点&#xff0c;问有多少种连法可以用n条线连接成n对点 输入样例 5输出样例 42解释&#xff1a; 一种可行的方案如下&#xff1a; 数据范围 对于30%数据&#xff1a; n<30。 对于100%数据&#xff1a; …

月旦评 之 DevOps招贤令2018

公元164-182年间&#xff0c;汝南平舆的许氏兄弟于每月初一品评人物&#xff0c;褒贬时政&#xff0c;被称为“月旦评”。所谓“子治世之能臣&#xff0c;乱世之奸雄也”这句许邵评价曹操的话也是来自于“月旦评”&#xff1b;时间一下子来到了2018年&#xff0c;LEANSOFT DevO…

函数式编程之-模式匹配(Pattern matching)

编者&#xff1a;C# 7.0也加入了模式匹配&#xff0c;来源于F#。模式匹配在F#是非常普遍的&#xff0c;用来对某个值进行分支匹配或流程控制。模式匹配的基本用法模式匹配通过match...with表达式来完成&#xff0c;一个完整的模式表达式长下面的样子&#xff1a;match [somethi…

Asp.Net Core SignalR 与微信小程序交互笔记

什么是Asp.Net Core SignalRAsp.Net Core SignalR 是微软开发的一套基于Asp.Net Core的与Web进行实时交互的类库&#xff0c;它使我们的应用能够实时的把数据推送给Web客户端。功能自动管理连接允许同时广播到所有客户端也可以广播到指定的组或者特定的客户端在Github上开源&am…

手机(jzoj 1983)

手机 jzoj 1983 题目大意&#xff1a; 在手机输入键盘上有很多键&#xff08;如下图&#xff09;&#xff0c;每一个位置按一次就是第一个字母&#xff0c;第二次就是第二个字母&#xff08;空格按0一次&#xff09;&#xff0c;现在问打出一条信息最少按几下&#xff1f; …

Go vs .NET Core 2.1

.NET Core 2.1 正式发布之际&#xff0c;微软团队在博客的中提到了 .NET Core 2.1 中的性能提升。这让我想起了去年 Go 语言 Iris MVC 框架作者做的 Go 与 .NET Core 2.0 之间的性能对比(具体可看https://hackernoon.com/go-vs-net-core-in-terms-of-http-performance-7535a61b…

.NET Core TDD 前传: 编写易于测试的代码 -- 依赖项

第1篇: 讲述了如何创造"缝". "缝"(seam)是需要知道的概念.第2篇, 避免在构建对象时写出不易测试的代码.本文是第3篇, 讲述依赖项和迪米特法则.迪米特法则 (Law of Demeter)还是使用建造汽车的例子. 生产汽车的时候需要轮胎, 组装时需要什么型号的轮胎, 就…

.Net Core中的日志组件(Logging)

1、介绍Logging组件是微软实现的日志记录组件包括控制台(Console)、调试(Debug)、事件日志(EventLog)和TraceSource&#xff0c;但是没有实现最常用用的文件记录日志功能(可以用其他第三方的如NLog、Log4Net。之前写过NLog使用的文章)。2、默认配置新建.Net Core Web Api项目&a…

将 ASP.NET Core 2.0 项目升级至 ASP.NET Core 2.1.3X

阅读文本大概需要 3.3 分钟。在上一篇文章《ASP.Net Core 运行错误 Http Error 502.5 解决办法》的最后有提到说&#xff0c;最推荐的升级办法是从2.0升级到2.1X版本.操作如下项目的例子直接使用https://github.com/52ABP/52ABP.School 作为对象&#xff0c;毕竟他正好是.NET C…

.net core 多版本如何选择

在讲述.net core多版本之前&#xff0c;我们先理解一下.net core sdk与.net core runtime之前的联系与区别&#xff0c;根据官网的解释我们可以简单地理解为&#xff1a;sdk是在开发过程中进行使用&#xff0c;而runtime是在项目发布后作为运行环境进行安装的&#xff0c;runti…

好代码是管出来的——使用GitHub实现简单的CI/CD

软件开发一般来说是一项团队作业&#xff0c;在本系列文章开始就提到过软件的编码是由一个团队“并行”完成的&#xff0c;为了保证编码任务正常完成&#xff0c;首先引入版本控制工具来完成代码管理&#xff0c;为了保证代码质量引入了代码分析器以及代码测试。版本控制工具可…

数据告诉你:中年并不只有危机,创业或许正当时

人们普遍认为最成功的企业家都是年轻人。比尔?盖茨、史蒂夫?乔布斯和马克?扎克伯格都在自己20岁出头的时候&#xff0c;建立起了日后改变世界的伟大公司。这些著名的案例是否反映了一种可以被普遍推广的模式呢&#xff1f;风险投资机构和媒体似乎赞成一点。我们分析了过去十…

ASP.NET Core 2.0 MVC项目实战

一、前言毕业后入职现在的公司快有一个月了&#xff0c;公司主要的产品用的是C/S架构&#xff0c;再加上自己现在还在学习维护很老的delphi项目&#xff0c;还是有很多不情愿的。之前实习时主要是做.NET的B/S架构的项目&#xff0c;主要还是用的那种传统的开发模式&#xff0c;…