通過silky框架在.net平臺構建微服務應用

Silky發表於2021-11-03

必要前提

  1. (必須) 安裝 .net5 或是 .net6 sdk。

  2. (必須) 您可以使用visual studio 或是rider作為開發工具。

  3. (必須) 您必須準備一個可用的zookeeper服務作為服務註冊中心。

  4. (必須) 使用選擇redis服務作為分散式快取服務。

使用Web主機構建微服務應用

開發者可以通過.net平臺提供Web 主機來構建silky微服務應用。

使用webhost來構建的Silky微服務應用,不但可以作為微服務應用的服務提供者(服務內部可以通過SilkyRpc框架進行通訊);也提供http服務,http請求通過應用服務方法(服務條目)生成的webapi,通過silky設定的路由規則即可訪問微服務應用提供的相關服務。

我們通過如下步驟可以快速的構建一個使用Web 主機構建的Silky微服務應用。

  1. 新增一個控制檯應用或是ASP.NET Core Empty應用

  1. 安裝Silky.Agent.Host

通過 Nuget Package Manger 安裝Silky.Agent.Host包:

或是通過控制檯命令安裝包:

PM> Install-Package Silky.Agent.Host -Version 3.0.2
  1. Main方法中構建silky主機
namespace Silky.Sample
{
    using Microsoft.Extensions.Hosting;
    using System.Threading.Tasks;
    class Program
    {
        public static async Task Main(string[] args)
        {
            await CreateHostBuilder(args).Build().RunAsync();
        }

        private static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Host.CreateDefaultBuilder(args)
                    .ConfigureSilkyWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
               
        }
    }
}
  1. 在啟用類中配置服務和置中介軟體、路由
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Silky.Http.Core;

namespace Silky.Sample
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            // 新增必要的服務
            services.AddSilkyHttpCore()
                .AddSwaggerDocuments()
                .AddRouting();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // 判斷是否開發環境
            if (env.IsDevelopment())
            {
                // 開發環境使用開發者異常調式頁面
                app.UseDeveloperExceptionPage();
                // 開發環境使用Swagger線上文件
                app.UseSwaggerDocuments();
            }

            // 使用路由中介軟體
            app.UseRouting();
            
            // 新增其他asp.net core中介軟體...

            // 配置路由
            app.UseEndpoints(endpoints => 
              { 
                // 配置SilkyRpc路由
                endpoints.MapSilkyRpcServices(); 
              });
        }
    }
}
  1. 更新配置

silky支援通過json或是yml格式進行配置。您可以通過appsettings.json為公共配置項指定配置資訊,也可以通過新增appsettings.${ENVIRONMENT}.json檔案為指定的環境更新配置屬性。

一般地,您必須指定rpc通訊的token,服務註冊中心地址等配置項。如果您使用redis作為快取服務,那麼您還需要將distributedCache:redis:isEnabled配置項設定為true,並給出redis服務快取的地址。

appsettings.json配置檔案中新增如下配置屬性:

{
  "RegistryCenter": {
    "Type": "Zookeeper",
    "ConnectionStrings": "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183;127.0.0.1:2184,127.0.0.1:2185,127.0.0.1:2186"
  },
  "DistributedCache": {
    "Redis": {
      "IsEnabled": true,
      "Configuration": "127.0.0.1:6379,defaultDatabase=0"
    }
  },
  "Rpc": {
    "Token": "ypjdYOzNd4FwENJiEARMLWwK0v7QUHPW",
    "Port": 2200
  }
}

將配置檔案屬性的複製到輸出目錄,設定為: 始終複製 或是 如果較新則複製

  1. 建立zookeeper服務和redis快取服務

在該示例專案中,我們使用Zookeeper作為服務註冊中心。我們在silky的示例專案中給出各種基礎服務的docker-compose的編排檔案,其中,也包括了zookeeper和redis服務的。

docker-compose.zookeeper.ymldocker-compose.redis.yml拷貝到本地,儲存為相同名稱的檔案,進入到儲存檔案的本地目錄。

# 建立一個名稱為silky_service_net的docker網路
docker network create silky_service_net

# 使用docker-compose建立zookeeper和redis服務
docker-compose -f docker-compose.zookeeper.yml -f docker-compose.redis.yml up -d
  1. 微服務應用的其他層(專案)

完成主機專案後,您可以新增應用介面層應用層領域層基礎設施層等其他專案,更多內容請參考微服務架構節點。

一個典型的微服務模組的劃分與傳統的DDD領域模型的應用劃分基本一致。需要將應用介面單獨的抽象為一個程式集,方便被其他微服務應用引用,其他微服務應用通過應用介面生成RPC代理,與該微服務通訊。

一個典型的微服務模組的專案結構如下所示:

專案的依賴關係如下:

(1) 主機專案依賴應用層,從而達到對應用的託管。

(2) 應用介面層用於定義服務介面和DTO物件,應用層需要依賴應用介面層,實現定義好的服務介面。

(3) 領域層主要用於實現具體的業務邏輯,可以依賴自身的應用介面層以及其他微服務應用的應用介面層(開發者可以通過nuget包安裝其他微服務應用的應用介面專案或是直接新增專案的方式進行引用);領域層依賴自身的應用介面層的原因是為了方便使用DTO物件;引用其他微服務的應用介面層可以通過介面生成的動態代理,與其他微服務通過SilkyRPC框架進行通訊。

(4) 領域共享層(Domain.Shared) 一般用於定義ddd概念中的值型別以及列舉等,方便被其他微服務應用引用。

(5) EntityFramework作為基礎服務層,提供資料訪問能力,當然,開發者也可以選擇使用其他ORM框架。

  1. 應用介面的定義和實現

應用介面層(Silky.Sample.Application.Contracts) 安裝包Silky.Rpc:

或是通過控制檯命令安裝包:

PM> Install-Package Silky.Rpc -Version 3.0.2

新增一個服務介面IGreetingAppService,並且定義一個Say()方法,應用介面需要使用[ServiceRoute]特性進行標識。

[ServiceRoute]
public interface IGreetingAppService
{
    Task<string> Say(string line);
}

接下來,我們需要 應用層(Silky.Sample.Application) 依賴(引用) 應用介面層(Silky.Sample.Application.Contracts), 並新增一個服務類GreetingAppService,通過它實現服務介面IGreetingAppService

    public class GreetingAppService : IGreetingAppService
    {
        public Task<string> Say(string line)
        {
            return Task.FromResult($"Hello {line}");
        }
    }
  1. 通過Swagger文件線上除錯

執行應用程式,即可開啟swagger線上文件。開發者可以通過swagger生成的線上文件除錯API。

使用.NET通用主機構建微服務應用

開發者可以通過.net平臺提供通用主機來構建silky微服務應用。

使用.NET 通用主機構建微服務應用只能作為服務提供者,通過SilkyRPC框架與其他微服務應用進行通訊;無法提供http服務,也就是說,叢集外部無法直接訪問該微服務應用,只能通過閘道器或是其他提供http服務的微服務應用訪問該微服務應用的服務。

使用.NET 通用主機構建Silky微服務應用的步驟與使用使用Web 主機構建微服務應用的步驟基本一致,區別在於無需配置Startup類,也不能配置http中介軟體(配置了也無效);開發者可以通過實現IConfigureService介面來完成對服務注入的配置。

1-2 步驟與使用web主機構建微服務應用一致。

  1. Main方法中構建silky主機
namespace Silky.Sample
{
    using Microsoft.Extensions.Hosting;
    using System.Threading.Tasks;
    class Program
    {
        public static async Task Main(string[] args)
        {
            await CreateHostBuilder(args).Build().RunAsync();
        }

        private static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Host.CreateDefaultBuilder(args)
                    .ConfigureSilkyGeneralHostDefaults();
               
        }
    }
}

建立ConfigureService類,用於實現IConfigureService介面,在ConfigureServices()方法中配置服務注入依賴。

   public class ConfigureService : IConfigureService
    {
        public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
        {
            services.AddSilkySkyApm()
                //其他服務(包括第三方元件的服務或是silky框架的其他服務,例如:Efcore元件,MessagePack編解碼,Cap或是MassTransit等分散式事件匯流排等)
                //...
                ;
        }
    }

5-7步驟與使用web主機構建微服務應用一致。

啟動應用後,我們可以在控制檯看到相關的日誌輸出,應用服務啟動成功。

使用者無法直接訪問該微服務應用,必須通過閘道器引用該微服務的 應用介面層 ,通過閘道器的提供的http服務間接的訪問該微服務應用提供的服務。

構建具有websocket服務能力的微服務應用

開發者通過構建具有websocket服務能力的微服務應用, 這樣的微服務應用可以除了可以作為服務提供者之外,還具有提供websocket通訊的能力(websocket埠預設為:3000)。可以通過與服務端進行握手會話(可以通過閘道器代理),服務端實現向客戶單推送訊息的能力。

構建具有websocket服務能力的微服務應用與使用.NET通用主機構建微服務應用的步驟一致,只是用於構建微服務應用的方法有差異。

1-2 步驟與使用web主機構建微服務應用一致。

  1. Main方法中構建silky主機
namespace Silky.Sample
{
    using Microsoft.Extensions.Hosting;
    using System.Threading.Tasks;
    class Program
    {
        public static async Task Main(string[] args)
        {
            await CreateHostBuilder(args).Build().RunAsync();
        }

        private static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureSilkyWebSocketDefaults();
    }
}

建立ConfigureService類,用於實現IConfigureService介面,在ConfigureServices()方法中配置服務注入依賴。

   public class ConfigureService : IConfigureService
    {
        public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
        {
            services.AddSilkySkyApm()
                //其他服務(包括第三方元件的服務或是silky框架的其他服務,例如:Efcore元件,MessagePack編解碼,Cap或是MassTransit等分散式事件匯流排等)
                //...
                ;
        }
    }

5-6步驟與使用web主機構建微服務應用一致。

  1. 構建具有提供websocket服務能力的服務

應用服務介面的定義與一般應用服務的介面定義一樣,只需要在一個普通的介面標識[ServiceRoute]特性即可。


[ServiceRoute]
public interface ITestAppService
{
   // 可以定義其他方法(服務條目),定義的方法可以與其他微服務應用通過RPC框架進行通訊
}

我們需要在 應用層(Silky.Sample.Application) 安裝 Silky.WebSocket包。

PM> Install-Package Silky.WebSocket -Version 3.0.2

並新增一個 TestAppService類, 通過它來實現 ITestAppService, 除此之外,我們需要 TestAppService類繼承 WsAppServiceBase基類。

    public class TestAppService : WsAppServiceBase, ITestAppService
    {
        private readonly ILogger<TestAppService> _logger;

        public TestAppService(ILogger<TestAppService> logger)
        {
            _logger = logger;
        }

        // 當建立websocket會話時
        protected override void OnOpen()
        {
            base.OnOpen();
            _logger.LogInformation("websocket established a session");
            
        }

        // 當服務端接收到客服端的訊息時
        protected override void OnMessage(MessageEventArgs e)
        {
            _logger.LogInformation(e.Data);
        }
        
       // 當websocket會話關閉時
        protected override void OnClose(CloseEventArgs e)
        {
            base.OnClose(e);
            _logger.LogInformation("websocket disconnected");
        }

        // 其他服務方法
    }

啟動應用後,我們可以在控制檯看到相關的日誌輸出,應用服務啟動成功。我們定義的websocket的服務的webapi地址為:/api/test

  1. 客戶端透過閘道器與websocket服務握手

客戶端無法直接與該微服務應用進行握手,必須通過閘道器引用該微服務的 應用介面層 ,通過閘道器的提供的websocket代理服務與該微服務進行握手,通過ws[s]://gateway_ip[:gateway_port]/websocket_webapi與之前定義websocket服務進行會話。

我們在構建的閘道器應用中引用該微服務的應用介面層,並啟動閘道器應用(閘道器服務地址為127.0.0.1:5000),並可通過地址:ws://127.0.0.1:5000/api/test與之前定義的websocket服務進行握手和通訊。

客戶端與websocket服務進行握手時,需要通過qstring引數或是請求頭設定hashkey,確保每次通訊的微服務應用都是同一個例項。

構建Silky微服務閘道器

實際上,通過.net平臺提供Web主機來構建silky微服務應用,也可以認為是一個閘道器。我們在這裡專門構建的閘道器與通過.net平臺提供Web 主機的區別在於該型別的微服務應用只能作為服務消費者,不能作為RPC服務提供者。

總的來說,閘道器是對微服務應用叢集來說是一個對接外部的流量入口。

構建過程與通過.net平臺提供Web 主機一致,我們只需要將建立主機的方法修改為:

 private static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureSilkyGatewayDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });

閘道器專案通過引用其他微服務應用的應用介面層,就可以作為服務消費者通過SilkyRPC框架呼叫其他微服務應用提供的服務,並且通過閘道器提供的http相關中介軟體可以實現生成線上swagger文件,實現統一的api鑑權,http限流,生成dashboard管理端,實現對微服務叢集服務提供者例項的健康檢查等功能。

開源地址

線上文件

線上示例

相關文章