一.什么Ocelot?
API網關是一個服務器,是系統的唯一入口。API 網關一般放到微服務的最前端,並且要讓API 網關變成由應用所發起的每個請求的入口。這樣就可以明顯的簡化客戶端實現和微服務應用程序之間的溝通方式。從面向對象設計的角度看,它與外觀模式類似。API網關封裝了系統內部架構,為每個客戶端提供一個定制的API。它可能還具有其它職責,如身份驗證、監控、負載均衡、緩存、請求分片與管理、靜態響應處理。
Ocelot 是一個使用在 .NET Core 平台上的一個 API Gateway,這個項目的目標是在 .NET 上面運行微服務架構。Ocelot 框架內部集成了 IdentityServer(身份驗證)和 Consul(服務注冊發現),還引入了 Polly 來處理進行故障處理。目前,騰訊和微軟Ocelot 在官網貼出來的客戶。
手把手搭建一個網關
在此之前你應該去學一學如何搭建服務集群,那么這將有效與你學習API網關服務,傳送門,再此基礎上再添加一個名為 MicroService.APIGetway 的ASP.NET WebApi項目。
在該項目中,我們通過Nuget安裝Ocelot,或者通過m命令行進行安裝。
注意:最新版的不建議使用,會出現一些內部錯誤,建議使用10.0.1以下的版本。
創建相關文件夾
在其中應該創建服務注冊以及網關文件夾,那么效果圖如下:
添加網關配置文件
在項目中,添加一個配置文件 ocelot.json ,並將文件屬性中 “賦值到輸出目錄” 的值修改為 “如果較新則復制”。
在ocelot.json文件夾中,加入以下內容。
{
"ReRoutes": [ { "UseServiceDiscovery": true, "DownstreamPathTemplate": "/api/values", "DownstreamScheme": "http", "ServiceName": "T169.OcelotConsul.Service", "LoadBalancerOptions": { "Type": "RoundRobin" }, "UpstreamPathTemplate": "/ss", "UpstreamHttpMethod": [ "Get", "Post" ], "ReRoutesCaseSensitive": false // non case sensitive } ], "GlobalConfiguration": { "ServiceDiscoveryProvider": { "Host": "localhost", // Consul Service IP "Port": 8500 // Consul Service Port } } }
以下是 Ocelot 官方給出的配置文件的節點說明
{
//官⽅方⽂文檔ReRoutes全節點示例例
"ReRoutes": [ { //Upstream表示上游請求,即客戶端請求到API Gateway的請求 "UpstreamPathTemplate": "/", //請求路路徑模板 "UpstreamHttpMethod": [ //請求⽅方法數組 "Get", "POST", "PUT", "DELETE", "OPTIONS" ], //Downstreamb表示下游請求,即API Gateway轉發的⽬目標服務地址 "DownstreamScheme": "http", //請求協議,⽬目前應該是⽀支持http和https "DownstreamHostAndPorts": [ { "Host": "localhost", //請求服務地址,應該是可以是IP及域名 "Port": 8081 //端⼝口號 } ], "DownstreamPathTemplate": "/", //下游請求地址模板 // 以下節點可選 "RouteClaimsRequirement": { //標記該路路由是否需要認證 "UserType": "registered" //示例例,K/V形式,授權聲明,授權token中 會包含⼀一些claim,如填寫則會判斷是否和token中的⼀一致,不不⼀一致則不不准訪問 }, //以下三個是將access claims轉為⽤用戶的Header Claims,QueryString,該 功能只有認證后可⽤用 "AddHeadersToRequest": { // "UserType": "Claims[sub] > value[0] > |", //示例例 "UserId": "Claims[sub] > value[1] > |" //示例例 }, "AddClaimsToRequest": {}, "AddQueriesToRequest": {}, "RequestIdKey": "", //設置客戶端的請求標識key,此key在請求header中 ,會轉發到下游請求中 "FileCacheOptions": { //緩存設置 "TtlSeconds": 15, //ttl秒被設置為15,這意味着緩存將在15秒后過期 。 "Region": "" //緩存region,可以使⽤用administrator API清除 }, "ReRouteIsCaseSensitive": false, //路路由是否匹配⼤大⼩小寫 "ServiceName": "", //服務名稱,服務發現時必填 "QoSOptions": { //斷路路器器配置,⽬目前Ocelot使⽤用的Polly "ExceptionsAllowedBeforeBreaking": 0, //打開斷路路器器之前允許的例例 外數量量。 "DurationOfBreak": 0, //斷路路器器復位之前,打開的時間(毫秒) "TimeoutValue": 0 //請求超時時間(毫秒) }, "LoadBalancer": "", //負載均衡 RoundRobin(輪詢)/LeastConnection( 最少連接數) "RateLimitOptions": { //官⽅方⽂文檔未說明 "ClientWhitelist": [], // 客戶端⽩白明代 ? "EnableRateLimiting": false, // 是否限流 ? "Period": "", "PeriodTimespan": 0, "Limit": 0 }, "AuthenticationOptions": { //認證配置 "AuthenticationProviderKey": "", //這個key對應的是代碼中.AddJW TBreark中的Key "AllowedScopes": [] //使⽤用范圍 }, "HttpHandlerOptions": { "AllowAutoRedirect": true, //指示請求是否應該遵循重定向響應。 如果請求應該⾃自動遵循來⾃自Downstream資源的重定向響應,則將其設置為true; 否則為假。 默認值是true。 "UseCookieContainer": true //該值指示處理理程序是否使⽤用CookieCon tainer屬性來存儲服務器器Cookie,並在發送請求時使⽤用這些Cookie。 默認值是true。 }, "UseServiceDiscovery": false //使⽤用服務發現,⽬目前Ocelot只⽀支持Consu l的服務發現 } ], "GlobalConfiguration": {} }
其中,我們需要了解一下微服務的上游服務器和下游服務器,以下是我個人的總結,下游服務器是提供Api接口,那么上游提供訪問的規則,下游服務器配置就是我們剛才創建的json里面的,我們指定Host,port,以及PathTemplate。
通過配置文件,我們可以可以知道Ocelot是通過我們的json配置規則映射成了它自己可以識別的對象,轉發給了后台的httpservice,從后端返回結果。
通過配置文件可以完成對 Ocelot 的功能配置: 路由、服務聚合、服務發現、認證、鑒權、限流、熔斷、緩存、 Header 頭傳遞 等。我們上面的配置說明都已經寫好了,比較重要的就是如下,下面你可以多留意。
- DownstreamPathTemplate:下游戲
- DownstreamScheme:下游服務http schema
- DownstreamHostAndPorts:下游服務的地址,如果使用LoadBalancer的話這里可以填多項
- UpstreamPathTemplate: 上游也就是用戶輸入的請求Url模板
- UpstreamHttpMethod: 上游請求http方法,可使用數組
修改啟動文件
public class Program
{
public static void Main(string[] args) { IWebHostBuilder builder = new WebHostBuilder(); builder.ConfigureServices(s => { s.AddSingleton(builder); }); builder.UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .ConfigureAppConfiguration((hostingContext, cfg) => { cfg.AddJsonFile("ocelot.json", false, true); }) .UseStartup<Startup>(); var host = builder.Build(); host.Run(); } }
這里需要引用一下包:
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
加載中間件
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddOcelot(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(); app.UseOcelot().Wait(); }
修改項目加載配置文件(launchsettings.json)
{
"profiles": { "WebApplication1": { "commandName": "Project", "launchBrowser": false, "launchUrl": "api/values", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "http://localhost:5000/" } } }
設置啟動多個項目
因為我們需要啟動服務,還有網關,我們就需要設置啟動多個項目了。右擊項目屬性。
講解
當然我們,還是要回顧以下服務器集群的服務發現是如何進行的。
這是一個很基本的json,如下圖,節點與項目之間的關系。
{
"services": [ { "ID": "OcelotConsul1_service", "name": "T169.OcelotConsul.Service", "tags": [ "urlprefix-/T169.Studeent.Service" ], "address": "localhost", "port": 8081, "checks": [ { "name": "Student Service check", "http": "http://localhost:8081/api/health", "interval": "10s", "timeout": "5s" } ] },{ "ID": "OcelotConsul2_service", "name": "T169.OcelotConsul.Service", "tags": [ "urlprefix-/T169.Studeent.Service" ], "address": "localhost", "port": 8080, "checks": [ { "name": "Student Service check", "http": "http://localhost:8080/api/health", "interval": "10s", "timeout": "5s" } ] } ] }
大家都知道我們在我們的服務中寫好了啟動端口和和ip地址,如以下定義。
{
"profiles": { "ConsulGoForProject": { "commandName": "Project", "applicationUrl": "http://localhost:8081", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } }
那么我們的配置文件就是通過address和port進行尋找的,尋找到之后,如果啟動集群,那么就會將這些節點轉換成對象,通過httpclient向集群進行映射,達到了一個這么一個功能,其中的ID應該是一個唯一的。那么name可以是相同的,可以讓網關進行一個發現,那么網關是根據什么進行分發的呢?
那么我們的網關是如何找到我們的服務的呢?
其中的DownstreamPathTemplate是向下的模板路徑,DownstreamScheme是訪問的方式,有http和https,ServiceName是服務發現的路徑,在此其中,你的配置文件中,如果和這個名字相同,那么就會根據對應的address和port 去訪問DownStreamPathTemplate,那么UpstreamPathTemplate是你要寫的別名,也就是說我們的台服務器無法達到匹配的時候,我們可以使用這個屬性(類似我們訪問www.baidu.com 第一次訪問和這個ServiceName相同的服務,第二次找第二個,當然這和Type:"RoundRobin" 這個屬性有極大的關聯,這個就叫做輪詢,這個屬性是Ocelot的精髓)。我們分別通過網關地址和服務的真實地址來訪問服務,看一看效果如何。
再此其中,我們使用開發模式進行啟動服務器集群。
consul agent -dev -config-dir=/tmp/consul/config
我們逐一將其中的api/values的控制器返回值改以下,這里就不貼代碼了,我們啟動項目,看一個細節。如下是剛啟動項目,還沒有啟動集群的時候是這個樣子的,這是大家都經常看到的。
我們開始部署集群,回車!,發現諸多的代碼在執行,如下圖所示,這是我們通過consul的命令去掃描了tmp/consul/config/ 這里面的json,當然它只認識json,讀取其中的節點,通過Consul的自動代理HttpClient注冊我們的服務,那么這就是一個通俗易懂的解釋了。
我們看一下網關的效果如何,我們發現這是非常榜的,這也就是輪詢機制,通過網關代理給我們帶來了極大的好處。
那么大家都知道WebApi限流機制,限流這個名詞我就不再解釋了,對請求進行限流可以防止下游服務器因為訪問過載而崩潰,這個功能就是我們的張善友張隊進添加進去的。非常優雅的實現,我們只需要在路由下加一些簡單的配置即可以完成。
"RateLimitOptions": {
"ClientWhitelist": [], "EnableRateLimiting": true, "Period": "1s", "PeriodTimespan": 1, "Limit": 1 }
- ClientWihteList 白名單
- EnableRateLimiting 是否啟用限流
- Period 統計時間段:1s, 5m, 1h, 1d
- PeroidTimeSpan 多少秒之后客戶端可以重試
- Limit 在統計時間段內允許的最大請求數量
總結
希望大家看完這篇可以有所收獲吧,Ocelot開源地址:https://github.com/TomPallister/Ocelot,如果有問題的話在下方留言。謝謝。!