.NET Core 搭建 Ocelot及使用

一、概念

Ocelot是一个用.NET Core实现并且开源的API网关,它功能强大,包括了:路由、请求聚合、服务发现、认证、鉴权、限流熔断、并内置了负载均衡器与Service Fabric、Butterfly Tracing集成。

二、API网关是什么?

API网关是系统暴露在外部的一个访问入口。就像一个公司的门卫承担着寻址、限制进入、安全检查、位置引导、等等功能。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理等等。.

API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。

三、Ocelot在API网关实现上有什么优点呢?

一句话,功能强大,使用简单。它的功能包括了:路由、请求聚合、服务发现、认证、鉴权、限流熔断、并内置了负载均衡器、Service Fabric、Skywalking等的集成。而且这些功能都只需要简单的配置即可完成。

四、Ocelot工作流程是怎样的呢?

实际上Ocelot就是一系列按特定顺序排列的中间件。

Ocelot首先通过配置将HttpRequest对象保存到一个指定的状态直到它到达用来创建HttpRequestMessage对象并将创建的HttpRequestMessage对象发送到下游服务中的请求构造中间件。通过中间件来发出请求是Ocelot管道中做的最后一件事。它不会再调用下一个中间件。下游服务的响应会存储在每个请求 scoped repository中,并作为一个请求返回到Ocelot管道中。有一个中间件将HttpResponseMessage映射到HttpResponse对象并返回给客户端。

五、集成图

1、基本集成

.NET Core 搭建 Ocelot及使用

2、集成 IdentityServer

.NET Core 搭建 Ocelot及使用

3、网关集群配置

.NET Core 搭建 Ocelot及使用

只有一个网关是很危险的,也就是我们通常所讲的单点,只要它挂了,所有的服务全挂。这显然无法达到高可用,所以我们也可以部署多台Ocelot网关。当然这个时候在多台网关前,你还需要一台负载均衡器。

4、结合Consul服务发现

.NET Core 搭建 Ocelot及使用

在Ocelot已经支持简单的负载功能,也就是当下游服务存在多个结点的时候,Ocelot能够承担起负载均衡的作用。

但是它不提供健康检查,服务的注册也只能通过手动在配置文件里面添加完成。这不够灵活并且在一定程度下会有风险。

这个时候我们就可以用Consul来做服务发现,它能与Ocelot完美结合。

5、结合Service Fabric

.NET Core 搭建 Ocelot及使用

六、.NET Core中如何使用ocelot。

Ocelot是系统中对外暴露的一个请求入口,所有外部接口都必须通过这个网关才能向下游API发出请求

1、Nuget引用Ocelot(注意版本,我用的是16.0.1)

2、根目录添加配置文件Ocelot.json

{   
    "ReRoutes": [],   
    "GlobalConfiguration": {}
}

说明:ReRoutes是一个数组,将会包含服务器的路由配置,GlobalConfiguration则是一个全局配置项。

3、修改Program.cs,引用添加的配置文件

.NET Core 搭建 Ocelot及使用

4、修改Startup.cs注册服务

.NET Core 搭建 Ocelot及使用

5、配置文件

配置如下:

.NET Core 搭建 Ocelot及使用
{
  //全局配置
  "GlobalConfiguration": {
    "BaseUrl": "http://192.168.50.118:8003/" //网关暴露的的地址。
  },
  //路由配置
  "routes": [
    {
      ///{url}转发所有
      //"UpstreamHost": "localhost:4023"转发特定服务
      "UpstreamPathTemplate": "/QiantoonService/Oam", //上游Api请求路由规则
      "DownstreamPathTemplate": "/QiantoonService/Oam/Oam", //网关转发到下游路由规则
      "UpstreamHttpMethod": [ "GET", "POST" ], //上下游支持请求方法
      "DownstreamScheme": "http", //下游服务配置
      "DownstreamHostAndPorts": [
        {
          "Host": "192.168.50.118", //下游地址
          "Port": 8001 //下游端口号
        }
      ]
    },
    {
      "UpstreamPathTemplate": "/QiantoonService/SelfReg", //上游Api请求路由规则
      "DownstreamPathTemplate": "/QiantoonService/SelfReg/SelfReg", //网关转发到下游路由规则
      "UpstreamHttpMethod": [ "GET", "POST" ], //上下游支持请求方法
      "DownstreamScheme": "http", //下游服务配置
      "DownstreamHostAndPorts": [
        {
          "Host": "192.168.50.118", //下游地址
          "Port": 8002 //下游端口号
        }
      ]
    }
  ]
}

其他说明:

GlobalConfiguration,它是一个全局配置项,通常我们都要在这个配置项中添加一个属性BaseUrl,BaseUrl就是Ocelot服务对外暴露的Url。

"GlobalConfiguration": {"BaseUrl": "http://localhost:4727"}

ReRoutes是一个数组,其中的每一个元素代表了一个路由,而一个路由所包含的所有可配置参数如下:

{    
    "DownstreamPathTemplate": "/",    
    "UpstreamPathTemplate": "/",    
    "UpstreamHttpMethod": 
    [        
        "Get"
    ],    
    "AddHeadersToRequest": {},    
    "AddClaimsToRequest": {},    
    "RouteClaimsRequirement": {},    
    "AddQueriesToRequest": {},    
    "RequestIdKey": "",    
    "FileCacheOptions": 
    {        
        "TtlSeconds": 0,        
        "Region": ""
    },    
    "ReRouteIsCaseSensitive": false,    
    "ServiceName": "",    
    "DownstreamScheme": "http",    
    "DownstreamHostAndPorts": 
    [
        {            
        "Host": "localhost",            
        "Port": 8001,
        }
    ],    
    "QoSOptions": 
    {        
        "ExceptionsAllowedBeforeBreaking": 0,        
        "DurationOfBreak": 0,        
        "TimeoutValue": 0
    },    
    "LoadBalancer": "",    
    "RateLimitOptions": 
    {        
        "ClientWhitelist": [],        
        "EnableRateLimiting": false,        
        "Period": "",        
        "PeriodTimespan": 0,        
        "Limit": 0
    },    
    "AuthenticationOptions": 
    {        
        "AuthenticationProviderKey": "",        
        "AllowedScopes": []
    },    
    "HttpHandlerOptions": 
    {        
        "AllowAutoRedirect": true,        
        "UseCookieContainer": true,        
        "UseTracing": true
    },    
    "UseServiceDiscovery": false
}

具体含义介绍:

  • Downstream 下游服务配置

  • UpStream 上游服务配置

  • Aggregates 服务聚合配置

  • ServiceName, LoadBalancer, UseServiceDiscovery 服务发现配置

  • AuthenticationOptions 服务认证配置

  • RouteClaimsRequirement Claims 鉴权配置

  • RateLimitOptions 限流配置

  • FileCacheOptions 缓存配置

  • QosOptions 服务质量与熔断配置

  • DownstreamHeaderTransform 头信息转发配置

注意

配置文件中“routes”关键字为新版本,旧版本关键字为“ReRoutes”

七、Ocelot请求聚合与负载均衡

1、请求聚合

1.1、概念

Ocelot可以定义多组路由,然后根据优先级对上游服务发出的请求进行不同的转发处理,每个路由转发都匹配唯一的一个下游服务API接口。

但是有时候,上游服务想要获得来自两个API接口返回的结果。Ocelot允许我们在配置文件中声明聚合路由Aggregates,从而实现这样的效果

1.2、路由配置

.NET Core 搭建 Ocelot及使用

可以看到这里多加了一个Key属性。Aggregates跟Routes是同级的,而且也是一个数组,这代表着我们可以声明多个聚合路由,而在我们声明的这一组聚合路由中的属性RouteKeys,它包含的元素就是我们真正需要响应的路由的Key属性值。

1.3、结果

.NET Core 搭建 Ocelot及使用
.NET Core 搭建 Ocelot及使用
.NET Core 搭建 Ocelot及使用

1.4、 注意事项

仅支持GET方式

下游服务返回类型要求为application/json

返回内容类型为application/json,不会返回404请求

此处必须返回Json,下游接口返回类型必须为IActionResult,如果返回String,那么聚合返回的下游json就会是乱码(别问我怎么知道的,又踩坑了)

2、高级请求聚合

自定义请求聚合,此处暂不过多说明,后续介绍

3、负载均衡

我们全部的路由配置中都是一组路由配置一个下游服务地址,也就说明当上游服务请求一个Url,Ocelot就必定转发给某一个固定的下游服务,这样其实是不安全的,因为有可能某一个下游服务阻塞,甚至挂掉了,那就可能导致整个服务瘫痪了,这肯定是不行的。Ocelot能够通过可用的下游服务对每个路由进行负载平衡。我们来看看具体的路由配置

.NET Core 搭建 Ocelot及使用

LeadConnection负载均衡器算法共有4种:

  • LeastConnection 把新请求发送到现有请求最少的服务上

  • RoundRobin 轮询可用的服务并发送请求

  • NoLoadBalancer 不负载均衡,总是发往第一个可用的下游服务

  • CookieStickySessions 使用cookie关联所有相关的请求到制定的服务

注意:经测,官网上面说的时轮询可用的服务,但是测试发现并不是,不可用的会报错

4、配置

{
  "GlobalConfiguration": {
    "BaseUrl": "http://192.168.50.118:8003/" //网关暴露的的地址。
  },
  "Routes": [
    {
      "UpstreamPathTemplate": "/QiantoonService/Oam", //上游Api请求路由规则
      "DownstreamPathTemplate": "/QiantoonService/Oam/Oam", //网关转发到下游路由规则
      "UpstreamHttpMethod": [ "Get" ], //上下游支持请求方法
      "DownstreamScheme": "http", //下游服务配置
      "DownstreamHostAndPorts": [
        {
          "Host": "192.168.50.118", //下游地址
          "Port": 8001 //下游端口号
        }
      ],
      "Key": "Oam"
    },
    {
      "UpstreamPathTemplate": "/QiantoonService/SelfReg", //上游Api请求路由规则
      "DownstreamPathTemplate": "/QiantoonService/SelfReg/SelfReg", //网关转发到下游路由规则
      "UpstreamHttpMethod": [ "Get" ], //上下游支持请求方法
      "DownstreamScheme": "http", //下游服务配置
      "DownstreamHostAndPorts": [
        {
          "Host": "192.168.50.118", //下游地址
          "Port": 8002 //下游端口号
        },
        {
          "Host": "192.168.50.118", //下游地址
          "Port": 8004 //下游端口号
        }
      ],
      "Key": "Reg",
      "LoadBalancerOptions": { "Type": "RoundRobin" }
    }
  ],
  "Aggregates": [
    {
      "RouteKeys": [
        "Oam",
        "Reg"
      ],
      "UpstreamPathTemplate": "/QiantoonService"
    }
  ]
}