1. 程式人生 > >.NET Core微服務之基於Steeltoe使用Eureka實現服務註冊與發現

.NET Core微服務之基於Steeltoe使用Eureka實現服務註冊與發現

一、關於Steeltoe與Spring Cloud

  

Steeltoe is an open source project that enables .NET developers to implement industry standard best practices when building resilient microservices for the cloud. The Steeltoe client libraries enable .NET Core and .NET Framework apps to easily leverage Netflix Eureka, Hystrix, Spring Cloud Config Server, and Cloud Foundry services.  

  我們主要關注的就是這句話:enable .NET Core and .NET Framework apps to easily leverage Netflix Eureka, Hystrix, Spring Cloud Config Server, and Cloud Foundry services  => 可以使我們的.NET/.NET Core應用程式輕鬆地使用Spring Cloud的一些核心元件如Eureka、Hystrix、Config Server以及雲平臺服務(例如PCF)。這裡也可以看出,目前Steeltoe的客戶端也僅僅支援輕鬆使用這幾個元件而已。

  Spring Cloud是一個基於Java的成熟的微服務全家桶架構,它為配置管理、服務發現、熔斷器、智慧路由、微代理、控制匯流排、分散式會話和叢集狀態管理等操作提供了一種簡單的開發方式,已經在國內眾多大中小型的公司有實際應用案例。許多公司的業務線全部擁抱Spring Cloud,部分公司選擇部分擁抱Spring Cloud。有關Spring Cloud的更多內容,有興趣的可以瀏覽我的這一篇《

Spring Cloud微服務架構學習筆記與基礎示例》,這裡不是本文重點,不再贅述。

二、快速構建Eureka Server

  (1)使用IDE (我使用的是IntelljIdea)新建一個Spring Boot應用程式

  (2)pom.xml中增加Spring Cloud的依賴和Eureka的starter

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- eureka server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <!-- spring cloud dependencies -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Edgware.SR3</version>
                <type>pom</type>
                <scope>import
</scope> </dependency> </dependencies> </dependencyManagement>

  (3)在啟動類上新增EnableEurekaServer註解

@SpringBootApplication
@EnableEurekaServer
public class EurekaServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServiceApplication.class, args);
    }
}

  (4)必要的Eureka配置

spring:
  application:
    name: eureka-server

server:
  port: 8761

eureka:
  server:
    enable-self-preservation: false          # 本地除錯環境下關閉自我保護機制
    eviction-interval-timer-in-ms: 5000      # 清理間隔時間,單位為毫秒
  instance:
    hostname: localhost
    #prefer-ip-address: true
  client:
    register-with-eureka: false
    fetch-registry: false

  PS:這裡關閉了Eureka的自我保護機制,是因為可以讓我們方便地看到服務被移除的效果。至於Eureka的自我保護機制,這是因為Eureka考慮到生產環境中可能存在的網路分割槽故障,會導致微服務與Eureka Server之間無法正常通訊。它的架構哲學是寧可同時保留所有微服務(健康的微服務和不健康的微服務都會保留),也不盲目登出任何健康的微服務。關於自我保護機制,更多內容可以參考:《Spring Cloud Eureka全解之自我保護機制》 

  (5)啟動專案,效果如下圖所示:暫時無任何服務註冊到該Eureka Server中

  

三、在ASP.NET Core中整合Eureka

3.1 快速準備幾個ASP.NET Core WebAPI

  

3.2 安裝Steeltoe服務發現客戶端並啟用

  分別對三個WebAPI通過Nuget安裝服務發現.NET Core客戶端(目前最新版本是2.1.0):

PM> Install-Package Pivotal.Discovery.ClientCore  

  按照慣例,需要在啟動類中啟用該客戶端:

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add Steeltoe Discovery Client service
        services.AddDiscoveryClient(Configuration);
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // 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();
        // Add Steeltoe Discovery Client service
        app.UseDiscoveryClient();
    }

3.3 Eureka Client必要配置

  分別對三個WebAPI進行如下配置(appSettings.json),下面以agent-service為例:

  "spring": {
    "application": {
      "name": "agent-service"
    }
  },
  "eureka": {
    "client": {
      "serviceUrl": "http://localhost:8761/eureka/",
      "shouldFetchRegistry": true,
      "validateCertificates": false
    },
    "instance": {
      "port": 8010,
      "preferIpAddress": true,
      "instanceId": "agent-service-container:8010"
    }
  }

  此外,如果想啟用Steeltoe的日誌,看到更多除錯資訊,可以加上以下配置:

"Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning",
      "Pivotal": "Debug",
      "Steeltoe": "Debug"
    }
  }

3.4 加入服務消費示例程式碼

  這裡假設其中的一個premium-service需要呼叫client-service的一個API介面,於是編寫了一個clientservice去消費API。這裡藉助一個加入了DiscoveryHttpClientHandler的HttpClient來進行目標地址的解析和請求,具體程式碼如下(這裡藉助的是.NET Core 2.1中提供的HttpClientFactory):

  (1)ClientService.cs

    public class ClientService : IClientService
    {
        private ILogger<ClientService> _logger;
        private readonly HttpClient _httpClient;

        public ClientService(HttpClient httpClient, ILoggerFactory logFactory = null)
        {
            _httpClient = httpClient;
            _logger = logFactory?.CreateLogger<ClientService>();
        }

        public async Task<string> GetClientName(int clientId)
        {
            var result = await _httpClient.GetStringAsync(clientId.ToString());
            _logger?.LogInformation($"GetClientName - ClientId:{clientId}");
            return result;
        }
    }

  (2)Startup.cs => 為了正確使用HttpClientFactory,需要在啟動類中新增一點配置,如下標粗顯示。

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IClientService, ClientService>();
            // Add Steeltoe Discovery Client service
            services.AddDiscoveryClient(Configuration);
            // Add Steeltoe handler to container
            services.AddTransient<DiscoveryHttpMessageHandler>();
            // Configure a HttpClient
            services.AddHttpClient("client-api-values", c =>
            {
                c.BaseAddress = new Uri(Configuration["Services:Client-Service:Url"]);
            })
            .AddHttpMessageHandler<DiscoveryHttpMessageHandler>()
            .AddTypedClient<IClientService, ClientService>();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // 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();
            // Add Steeltoe Discovery Client service
            app.UseDiscoveryClient();
        }
    }

  這裡在注入HttpClient時,AddTypedClient<IClientService, ClientService>() 表明注入的這個HttpClient是給這個型別用的。而AddHttpMessageHandler<DiscoveryHttpMessageHandler>() 則表明使用這個HttpClient的時候,會使用這個Handler (DiscoveryHttpMessageHandler)。

  另外,這裡的Uri來自appSettings.json配置檔案中:

  "Services": {
    "Client-Service": {
      "Url": "http://client-service/api/values/"
    }
  }

  這裡摘抄一段老九大大(老九大大對HttpClient有著比較深入的瞭解,一直在維護WebApiClient專案)的文章裡面的原話:“HttpClientFactory用於提供HttpClient的建立和生命週期自動管理,完美解決到底選擇單例還是每個請求建立和釋放HttpClient這個左右難為的問題。所以在asp.net core專案開發中,請別再寫手動new HttpClient了,所有HttpClient的例項,都要由HttpClientFactory來建立,所有的外部HttpMessageHandler,也應該配置到HttpClientFactory,讓它與HttpClient關聯起來。”

  此外,最近看到了老九大大針對SteeltoeOSS.DiscoveryClient進行了擴充套件,我們可以在這種架構(ASP.NET Core + Spring Cloud)下使用WebApiClient了,它可以讓我們像使用Feign一樣實現宣告式的REST呼叫,提高編碼效率。

PM> Install-Package WebApiClient.Extensions.DiscoveryClient

  關於如何使用這個WebApiClient的擴充套件WebApiClient.Extensions.DiscoveryClient,可以參考老九大大的這一篇《WebApiClient的SteeltoeOSS.Discovery擴充套件》。

四、快速驗證性測試

4.1 啟動三個WebAPI,檢視服務是否註冊到Eureka

  

  可以看到,三個服務均已成功註冊到Eureka Server。

4.2 關閉Agent-Service,檢視Eureka Server是否移除該服務

  

  可以看到,Agent-Service已被Eureka移除。

4.3 啟動多個Client-Service例項,檢視Eureka Server服務列表

  

  可以看到,Client-Service的兩個例項都已註冊。

4.4 從Premium-Service消費Client-Service,驗證是否能成功消費

  第一次呼叫:

  

  第二或第三次呼叫:

  

  可以看到,客戶端每次(不一定是每次)解析得到的都是服務叢集中的不同例項節點,因此也就實現了類似於Ribbon的客戶端的負載均衡效果。

五、小結

  本文簡單地介紹了一下Steeltoe與Spring Cloud,然後演示了一下基於Steeltoe使得ASP.NET Core應用程式與Spring Cloud Eureka進行整合以實現服務註冊與發現的效果。更多內容,請參考Steeltoe官方文件示例專案。對於已有Spring Cloud微服務架構環境的專案,如果想要ASP.NET Core微服務與Java Spring Boot微服務一起共享Spring Cloud Eureka來提供服務,基於Steeltoe是一個選擇(雖然覺得不是最優,畢竟是寄居)。

示例程式碼

參考資料

作者:周旭龍

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。