.Net Core微服務入門全紀錄(四)——Ocelot-API閘道器(上)

xhznl發表於2020-06-17

前言

上一篇【.Net Core微服務入門全紀錄(三)——Consul-服務註冊與發現(下)】已經使用Consul完成了服務的註冊與發現,實際中光有服務註冊與發現往往是不夠的,我們需要一個統一的入口來連線客戶端與服務。

Ocelot

官網:https://ocelot.readthedocs.io/
Ocelot正是為.Net微服務體系提供一個統一的入口點,稱為:Gateway(閘道器)。

  • 上手Ocelot:

首先建立一個空的asp.net core web專案。

注意ocelot.json是我們新增的Ocelot的配置檔案,記得設定生成時複製到輸出目錄。ocelot.json的檔名不是固定的,可以自己定義。

NuGet安裝一下Ocelot:

只需簡單的修改幾處預設程式碼:
Program.cs:

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddJsonFile("ocelot.json");
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Startup.cs:

    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            //新增ocelot服務
            services.AddOcelot();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //設定Ocelot中介軟體
            app.UseOcelot().Wait();
        }
    }

ocelot.json:

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/products",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 9050
        },
        {
          "Host": "localhost",
          "Port": 9051
        },
        {
          "Host": "localhost",
          "Port": 9052
        }
      ],
      "UpstreamPathTemplate": "/products",
      "UpstreamHttpMethod": [
        "Get"
      ],
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //負載均衡,輪詢機制 LeastConnection/RoundRobin/NoLoadBalancer/CookieStickySessions
      }
    },
    {
      "DownstreamPathTemplate": "/orders",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 9060
        },
        {
          "Host": "localhost",
          "Port": 9061
        },
        {
          "Host": "localhost",
          "Port": 9062
        }
      ],
      "UpstreamPathTemplate": "/orders",
      "UpstreamHttpMethod": [
        "Get"
      ],
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //負載均衡,輪詢機制 LeastConnection/RoundRobin/NoLoadBalancer/CookieStickySessions
      }
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:9070"
  }
}

我們先暫時忽略Consul,將服務例項的地址都寫在配置檔案中。要知道Consul、Ocelot等元件都是可以獨立存在的。
配置檔案中的Routes節點用來配置路由,Downstream代表下游,也就是服務例項,Upstream代表上游,也就是客戶端。我們的路徑比較簡單,只有/products、/orders,路徑中如果有不固定引數則使用{}匹配。我們這個配置的意思呢就是客戶端訪問閘道器的/orders、/products,閘道器會轉發給服務例項的/orders、/products,注意這個上游的路徑不一定要和下游一致,比如上游路徑可以配置成/api/orders,/xxx都可以。
LoadBalancerOptions節點用來配置負載均衡,Ocelot內建了 LeastConnection、RoundRobin、NoLoadBalancer、CookieStickySessions 4種負載均衡策略。
BaseUrl節點就是配置我們ocelot閘道器將要執行的地址。

  • 執行gateway:

目前不考慮閘道器叢集,就不放在docker裡了。直接控制檯執行:`dotnet Ocelot.APIGateway.dll --urls="http://*:9070"

用瀏覽器測試一下:


測試正常,我們通過閘道器可以正常的訪問到服務例項。

  • 接下來繼續改造客戶端程式碼:


因為改動太多就直接新建一個GatewayServiceHelper來做。
GatewayServiceHelper:

    /// <summary>
    /// 通過gateway呼叫服務
    /// </summary>
    public class GatewayServiceHelper : IServiceHelper
    {
        public async Task<string> GetOrder()
        {
            var Client = new RestClient("http://localhost:9070");
            var request = new RestRequest("/orders", Method.GET);

            var response = await Client.ExecuteAsync(request);
            return response.Content;
        }

        public async Task<string> GetProduct()
        {
            var Client = new RestClient("http://localhost:9070");
            var request = new RestRequest("/products", Method.GET);

            var response = await Client.ExecuteAsync(request);
            return response.Content;
        }

        public void GetServices()
        {
            throw new NotImplementedException();
        }
    }

然後在Startup中修改一下注入的型別,別的就不用改了,這就是依賴注入的好處之一。。。
Startup.ConfigureServices():

//注入IServiceHelper
//services.AddSingleton<IServiceHelper, ServiceHelper>();
            
//注入IServiceHelper
services.AddSingleton<IServiceHelper, GatewayServiceHelper>();

Startup.Configure():

//程式啟動時 獲取服務列表
//serviceHelper.GetServices();

執行客戶端測試:

好了,現在客戶端對服務的呼叫都通過閘道器進行中轉,客戶端再也不用去關心那一堆服務例項的地址,只需要知道閘道器地址就可以了。另外,服務端也避免了服務地址直接暴露給客戶端。這樣做對客戶端,服務都非常友好。

至於我們的api閘道器呢,又要說到服務發現的問題了。目前我們的服務地址是寫在ocelot.json配置檔案裡的,當然這種做法在服務例項不經常變化的情況下是沒有問題的,一旦服務變化,需要人為的修改配置檔案,這又顯得不太合理了。

當然,強大的Ocelot為我們提供了服務發現的方案。

程式碼放在:https://github.com/xiajingren/NetCoreMicroserviceDemo

未完待續...

相關文章