Tip: 此篇已加入.NET Core微服務基礎系列文章索引
=> Steeltoe目錄快速導航:
1. 基於Steeltoe使用Spring Cloud Eureka
2. 基於Steeltoe使用Spring Cloud Zuul
3. 基於Steeltoe使用Spring Cloud Hystrix
一、關於Steeltoe與Spring Cloud
Steeltoe的官方地址:http://steeltoe.io/,其官方介紹如下:
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" } }
PS:更多配置屬性的說明,請參考:http://steeltoe.io/docs/steeltoe-discovery/
此外,如果想啟用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關聯起來。”
關於更多的如何使用HttpClientFactory在.NET Core 2.1下的使用姿勢,請參考這一篇:《3 ways to use HTTPClientFactory in ASP.NET Core 2.1》。
此外,最近看到了老九大大針對SteeltoeOSS.DiscoveryClient進行了擴展,我們可以在這種架構(ASP.NET Core + Spring Cloud)下使用WebApiClient了,它可以讓我們像使用Feign一樣實現聲明式的REST調用,提高編碼效率。
PM> Install-Package WebApiClient.Extensions.DiscoveryClient
關於如何使用這個WebApiClient的擴展WebApiClient.Extensions.DiscoveryClient,可以參考老九大大的這一篇《WebApiClient的SteeltoeOSS.Discovery擴展》。
而關於WebApiClient的使用,我也有寫一篇短文《.NET Core微服務之服務間的調用(REST and RPC)》。
四、快速驗證性測試
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是一個選擇(雖然覺得不是最優,畢竟是寄居)。
示例代碼
點擊這里 => https://github.com/EdisonChou/Microservice.PoC.Steeltoe
參考資料
Steeltoe官方文檔:《Steeltoe Doc》
Steeltoe官方示例:https://github.com/SteeltoeOSS/Samples
蟋蟀,《.NET Core 微服務架構 Steeltoe的使用》
nerocloud,《Spring Cloud 和 .NET Core 實現微服務架構》
龍應輝,《Spring Cloud + .NET Core 搭建微服務架構》
黃文清,《HttpClientFactory與Steeltoe結合來完成服務發現》
老九,《WebApiClient的SteeltoeOSS.Discovery擴展》=> 好文,推薦閱讀