1. 程式人生 > >.net core 微服務之Api網關(Api Gateway)

.net core 微服務之Api網關(Api Gateway)

代理類 prism sem msg 線上 olly invoke web -o

原文:.net core 微服務之Api網關(Api Gateway)

微服務網關目錄

      • 1、 微服務引子
      • 2、使用Nginx作為api網關
      • 3、自創api網關(重復輪子)
        • 3.1、構建初始化
        • 3.2、構建中間件
      • 4、結語
  • 引用鏈接

1、 微服務引子

首先恭喜你,進入微服務的開發世界。微服務屬於架構演進中的一種階段,其特點是根據業務模塊水平劃分服務種類,每個服務可以獨立部署並互相隔離,並對外提供輕量的Api調用,服務具有高可用特性。

微服務應遵循的設計原則:

  • 單一職責原則: 每個微服務只需要實現自己的業務邏輯
  • 服務自治原則: 每個微服務都是獨立的,不依賴其他模塊
  • 輕量級通信原則:一般采用Http + Json方式
  • 接口明確原則:接口盡量做的更通用,更靈活,從而盡量避免接口參數的來回修改。

我從2017年12月開始接觸微服務概念,並開始著手構建公司的微服務平臺,系統架構采用 .net core webapi方式組織,隨著微服務的增多,越來越需要一個統一入口管理這些微服務。

2、使用Nginx作為api網關

Nginx是由IgorSysoev為俄羅斯訪問量第二的Rambler.ru站點開發的,一個高性能的HTTP和反向代理服務器。2012年,Nginx榮獲年度雲計算開發獎,並成長為世界第二大Web服務器。全世界流量最高的前1000名網站中,超過25%都使用Nginx來處理海量的互聯網請求。

Nginx很牛掰,業界公認的首選,選擇它作為api網關,可以說不用開發介入,只需要運維的同學好好規劃配置即可。
技術分享圖片

網關配置規劃如下:
/api/ServiceA —> ServiceA
/api/ServiceB —> ServiceB
/api/ServiceC —> ServiceC
外部統一的訪問入口是Nginx,然後根據服務名稱路由到不同的微服務站點。
api網關的路由難題解決了,其他熔斷,灰度發布,線上測試,日誌攔截等功能nginx做起來相對比較吃力,不過對於中小型平臺已經夠用了。

3、自創api網關(重復輪子)

半年後,換了家公司,公司微服務平臺搭建采用Thrift RPC

作為各個微服務的通訊協議,由於當時的無知(Socket協議已被Nginx支持),所以決定寫個Api代理類,沒敢叫Api網關,是因為實現的功能僅限於路由!
僅僅是路由,當然是祭出 .net core Web應用。

3.1、構建初始化

MVC框架包就別包含了,輕量的性能才能好!
Main函數初始化線程池大小

			//初始化線程池最小大小 為 300
           ThreadPool.GetMinThreads(out var wt, out var ct);
           if (wt < 300 || ct < 300)
           {
               ThreadPool.SetMinThreads(Math.Max(wt, 300), Math.Max(ct, 300));
           }

**註意:**線程池不是越大越好,最佳選擇約等於 cpu內核的2倍,有個公式參考:
技術分享圖片
多說一句吧,思考下:

為什麽Nginx只用4個線程發揮出的性能就大大超越了100個進程的Apache HTTPD?回想一下計算機科學的基礎知識,答案其實是很明顯的。

我要支持跨域訪問:

public void ConfigureServices(IServiceCollection services)
{
      services.AddCors(options =>
      {
          options.AddPolicy("AllowAll", p => p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials());
      });       
  }

配置下使用中間件

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
       {           
           app.UseCors("AllowAll");
           app.UseMiddleware<ProxyMiddleware>();
           // app.UseMvc();
       }

3.2、構建中間件

路由轉發,一個中間件即可搞定。

    public class ProxyMiddleware
   {
       private readonly RequestDelegate m_Next;

       public ProxyMiddleware(RequestDelegate next)
       {
           this.m_Next = next;
       }

       public Task Invoke(HttpContext context)
       {
           if (context.Request.Method?.ToUpper() == "GET")
           {
               var path = context.Request.Path.HasValue ? context.Request.Path.ToString().ToLower() : string.Empty;
               if (string.IsNullOrEmpty(path) || path.Equals("/") || path.Equals("/api") || path.Equals("/api/"))
               {
                   return this.SendConstRespond(context);
               }
               //增加一個代理網關接口,返回微服務列表
               else if (path.EndsWith("/getallservices"))
               {
                   return this.SendServiceListRespond(context);
               }

               return this.SendStringRespond(context);
           }

           if (context.Request.ContentType == null || context.Request.ContentType.IndexOf("application/json") < 0)
           {
               context.Response.StatusCode = 403;
               context.Response.ContentType += "application/json;charset=utf-8;";
               return context.Response.WriteAsync("Please set ContentType=application/json");
           }

           return this.SendStringRespond(context);
       }

       private Task SendStringRespond(HttpContext context)
       {
           context.Response.StatusCode = 200;
           context.Response.ContentType += "application/json;charset=utf-8;";

           Task task = new Task(() =>
           {
               if (ServerSetting.Config.QuantumConfig.RpcService.ServerType==ServerType.HttpWebApi)
               {
                  string constResp = QuantumHttpProxy.SendHttp(context);
                   using (var strStream = new StreamWriter(context.Response.Body))
                   {
                       strStream.Write(constResp);
                       strStream.Flush();
                   }
               }
               else
               {
                   QuantumHttpProxy.Send(context);
               }
           });
           task.Start();

           return task;
       }

       private Task SendConstRespond(HttpContext context)
       {
           context.Response.StatusCode = 200;
           context.Response.ContentType += "application/json;charset=utf-8;";

           Task task = new Task(() =>
           {
               var constResp = new
               {
                   rid = string.Empty,
                   c = 200,
                   msg = "Access api gateway success!"
               };
               using (var strStream = new StreamWriter(context.Response.Body))
               {
                   strStream.Write(JsonConvert.SerializeObject(constResp));
                   strStream.Flush();
               }
           });
           task.Start();
           return task;
       }
       private Task SendServiceListRespond(HttpContext context)
       {
           context.Response.StatusCode = 200;
           context.Response.ContentType += "application/json;charset=utf-8;";

           Task task = new Task(() =>
           {
               var svrs = ServerSetting.Config?.HttpProxy?.Items?.Select(x => x.Name)?.ToList() ?? new List<string>();
               var constResp = new
               {
                   rid = Guid.NewGuid().ToString("N"),
                   c = 200,
                   v = svrs,
               };
               using (var strStream = new StreamWriter(context.Response.Body))
               {
                   strStream.Write(JsonConvert.SerializeObject(constResp));
                   strStream.Flush();
               }
           });
           task.Start();
           return task;
       }
   }

上面的代碼裏 有 QuantumHttpProxy,是我們封裝的rpc調用,因此各位同學要用此類,請自行修改之。

4、結語

沒有重試,熔斷也沒有降級,是否很low?
這就是實際實踐的力量,不必耗費太多精力在一些非關鍵點上!
好吧,我承認我研究了 **polly**類庫,重試,熔斷,降級都準備好了,你就起航吧~~~
另外:造輪子只適合特定場景,小投入就可以完成的某些特定功能,比如上面的路由功能!如果你是雲服務,可以重點考慮下 阿裏API網關,亞馬遜api網關!

引用鏈接

  1. 口袋代碼倉庫
  2. 在線計算器
  3. 本節源碼:github

.net core 微服務之Api網關(Api Gateway)