閱讀目錄:
- 1. Spring Cloud Eureka 注冊服務及調用
- 2. Spring Cloud Hystrix 斷路器
- 3. Spring Cloud Hystrix 指標監控
- 4. Spring Cloud Config 配置中心
現在主流的開發平台是微服務架構,在眾多的微服務開源項目中,Spring Cloud 非常具有代表性,但實現平台是基於 Java,那在 .NET Core 平台下,如何兼容實現 Spring Cloud 呢?答案就是 Steeltoe,或者你也可以自行實現,因為 Spring Cloud 各組件基本都是基於 REST HTTP 接口實現,你可以使用任何語言實現兼容。
關於 Steeltoe 的官方介紹:
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.
這邊就不翻譯了,需要注意的幾點:
- Netflix Eureka:服務注冊中心,實現服務注冊,以及服務發現調用。
- Hystrix:斷路器,實現熔斷處理。
- Spring Cloud Config Server:分布式配置中心,主要是讀取配置中心的信息。
- Cloud Foundry:開源 PaaS 雲平台,Steeltoe 基本都運行在此平台上,運行在其他平台兼容不好。
另外,Steeltoe 不僅支持 .NET Core,還支持 .NET Framework(具體 ASP.NET 4.x 版本)。
1. Spring Cloud Eureka 注冊服務及調用
項目代碼:https://github.com/yuezhongxin/Steeltoe.Samples/tree/master/Discovery-CircuitBreaker/AspDotNetCore
首先,需要部署一個或多個 Spring Cloud Eureka 服務注冊中心,可以使用 Spring Boot 很方便進行實現,這邊就不說了。
創建一個 APS.NET Core 應用程序(2.0 版本),然后 Nuget 安裝程序包:
> install-package Pivotal.Discovery.ClientCore
在appsettings.json
配置文件中,增加下面配置:
{
"spring": {
"application": {
"name": "fortune-service"
}
},
"eureka": {
"client": {
"serviceUrl": "http://192.168.1.32:8100/eureka/",
"shouldFetchRegistry": true, //Enable or disable registering as a service
"shouldRegisterWithEureka": true, //Enable or disable discovering services
"validate_certificates": false
},
"instance": {
//"hostName": "localhost",
"port": 5000
}
}
}
這樣我們啟動 APS.NET Core 應用程序,就會將fortune-service
服務注冊到 Eureka 中了。
EUREKA-CLIENT
是用 Spring Boot 實現的一個服務,下面我們測試FORTUNE-SERVICE
如何調用EUREKA-CLIENT
。
創建一個IEurekaClientService
接口:
public interface IEurekaClientService
{
Task<string> GetServices();
}
然后再創建IEurekaClientService
接口的實現EurekaClientService
:
public class EurekaClientService : IEurekaClientService
{
DiscoveryHttpClientHandler _handler;
private const string GET_SERVICES_URL = "http://eureka-client/home";
private ILogger<EurekaClientService> _logger;
public EurekaClientService(IDiscoveryClient client, ILoggerFactory logFactory = null)
:base(options)
{
_handler = new DiscoveryHttpClientHandler(client, logFactory?.CreateLogger<DiscoveryHttpClientHandler>());
_logger = logFactory?.CreateLogger<EurekaClientService>();
}
public async Task<string> GetServices()
{
_logger?.LogInformation("GetServices");
var client = GetClient();
return await client.GetStringAsync(GET_SERVICES_URL);
}
private HttpClient GetClient()
{
var client = new HttpClient(_handler, false);
return client;
}
}
然后創建一個FortunesController
:
[Route("api")]
public class FortunesController : Controller
{
private IEurekaClientService _eurekaClientService;
private ILogger<FortunesController> _logger;
public FortunesController(IEurekaClientService eurekaClientService, ILogger<FortunesController> logger)
{
_eurekaClientService = eurekaClientService;
_logger = logger;
}
// GET: api/services
[HttpGet("services")]
public async Task<IActionResult> GetServices()
{
_logger?.LogInformation("api/services");
return Ok(await _eurekaClientService.GetServices());
}
}
最后在Startup.cs
中,添加如下配置:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// 加載服務注冊配置
services.AddDiscoveryClient(Configuration);
// Add framework services.
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime lifetime)
{
app.UseStaticFiles();
app.UseMvc();
// 啟動服務注冊
app.UseDiscoveryClient();
}
}
然后重新啟動服務,執行命令:
$ curl http://192.168.1.3:5000/api/services
Services(get all by DiscoveryClient): [eureka-client, fortune-service]%
可以看到,調用是成功的,實際調用的是EUREKA-CLIENT
服務的接口,獲取的是 Eureka 注冊中心,所有的注冊服務信息。
ASP.NET 4.x 版本的實現,和上面的類似,這邊就不敘述了,可以查看項目代碼:https://github.com/yuezhongxin/Steeltoe.Samples/tree/master/Discovery-CircuitBreaker/AspDotNet4
2. Spring Cloud Hystrix 斷路器
項目代碼:https://github.com/yuezhongxin/Steeltoe.Samples/tree/master/Configuration/AspDotNetCore
Spring Cloud Hystrix 的實現,需要我們對上面的項目進行改造下。
IEurekaClientService
增加一個GetServicesWithHystrix
接口:
public interface IEurekaClientService
{
Task<string> GetServices();
Task<string> GetServicesWithHystrix();
}
然后對其進行實現:
public class EurekaClientService : HystrixCommand<string>, IEurekaClientService
{
DiscoveryHttpClientHandler _handler;
private const string GET_SERVICES_URL = "http://eureka-client/home";
private ILogger<EurekaClientService> _logger;
public EurekaClientService(IHystrixCommandOptions options, IDiscoveryClient client, ILoggerFactory logFactory = null)
:base(options)
{
_handler = new DiscoveryHttpClientHandler(client, logFactory?.CreateLogger<DiscoveryHttpClientHandler>());
IsFallbackUserDefined = true;
_logger = logFactory?.CreateLogger<EurekaClientService>();
}
public async Task<string> GetServices()
{
_logger?.LogInformation("GetServices");
var client = GetClient();
return await client.GetStringAsync(GET_SERVICES_URL);
}
public async Task<string> GetServicesWithHystrix()
{
_logger?.LogInformation("GetServices");
var result = await ExecuteAsync();
_logger?.LogInformation("GetServices returning: " + result);
return result;
}
protected override async Task<string> RunAsync()
{
_logger?.LogInformation("RunAsync");
var client = GetClient();
var result = await client.GetStringAsync(GET_SERVICES_URL);
_logger?.LogInformation("RunAsync returning: " + result);
return result;
}
protected override async Task<string> RunFallbackAsync()
{
_logger?.LogInformation("RunFallbackAsync");
return await Task.FromResult("This is a error(服務斷開,稍后重試)!");
}
private HttpClient GetClient()
{
var client = new HttpClient(_handler, false);
return client;
}
}
然后還需要在Startup.cs
中添加注入:
public void ConfigureServices(IServiceCollection services)
{
// Register FortuneService Hystrix command
services.AddHystrixCommand<IEurekaClientService, EurekaClientService>("eureka-client", Configuration);
}
然后重啟服務,執行命令:
$ curl http://192.168.1.3:5000/api/services/hystrix
Services(get all by DiscoveryClient): [eureka-client, fortune-service]%
Hystrix 斷路器的作用,體現在調用服務出現問題不能訪問,這邊可以進行熔斷處理,我們把eureka-client
服務停掉,然后再進行訪問測試:
$ curl http://192.168.1.3:5000/api/services/hystrix
This is a error(服務斷開,稍后重試)!%
可以看到,Hystrix 起到了作用。
ASP.NET 4.x 版本的實現,和上面的類似,這邊就不敘述了,可以查看項目代碼:https://github.com/yuezhongxin/Steeltoe.Samples/tree/master/Discovery-CircuitBreaker/AspDotNet4
3. Spring Cloud Hystrix 指標監控
項目代碼:https://github.com/yuezhongxin/Steeltoe.Samples/tree/master/Discovery-CircuitBreaker/AspDotNetCore
在實際應用中,我們需要對 Hystrix 斷路器進行監控,比如熔斷請求有多少等等,Spring Cloud 中的實現有 Turbine 進行收集,數據展示的話使用 Hystrix Dashboard。
這邊需要我們先創建一個 Hystrix Dashboard 項目,我使用的 Spring Boot 進行實現,這邊就不敘述了。
我們需要再對上面的項目進行改造,在Startup.cs
中添加配置,以啟動 Hystrix 指標監控。
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Add Hystrix metrics stream to enable monitoring
services.AddHystrixMetricsStream(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime lifetime)
{
// Startup Hystrix metrics stream
app.UseHystrixMetricsStream();
}
}
另外,還需要配置下Fortune-Teller-Service.csproj
:
<ItemGroup Condition="'$(BUILD)' == 'LOCAL'">
<PackageReference Include="Steeltoe.CircuitBreaker.Hystrix.MetricsStreamCore" Version="2.0.0" />
<PackageReference Include="RabbitMQ.Client" Version="5.0.1" />
</ItemGroup>
<ItemGroup Condition="'$(BUILD)' == ''">
<PackageReference Include="Steeltoe.CircuitBreaker.Hystrix.MetricsEventsCore" Version="2.0.0" />
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
</ItemGroup>
然后重啟項目,然后瀏覽器打開:http://192.168.1.3:5000/hystrix/hystrix.stream
會看到不斷實時刷新的 Hystrix 指標監控數據了,但顯示並不友好,我們還需要在儀表盤中顯示。
瀏覽器打開 Hystrix Dashboard(地址:http://192.168.1.31:8170/hystrix),然后在輸入框中輸入:http://192.168.1.3:5000/hystrix/hystrix.stream
然后點擊 Monitor Stream 按鈕,就可以看到 Hystrix 圖形化監控了(多次請求http://192.168.1.3:5000/api/services/hystrix
,以便測試):
另外,ASP.NET 4.x 版本配置的話,訪問http://192.168.1.3:5000/hystrix/hystrix.stream
會報 404 錯誤,原因是 ASP.NET 4.x 版本暫不支持 Cloud Foundry 以外的平台,詳情參見:

4. Spring Cloud Config 配置中心
項目代碼:https://github.com/yuezhongxin/Steeltoe.Samples/tree/master/Configuration/AspDotNetCore
需要注意的是,這邊只測試 Steeltoe 讀取配置中心數據,需要先開發一個 Spring Cloud Config Server 配置中心服務,這邊就不敘述了。
我使用的 GitHub 作為配置中心倉庫,xishuai-config-dev.yml配置詳情:
info:
profile: dev
name: xishuai7
password: '{cipher}AQAc+v42S+FW7H5DiATfeeHY887KLwmeBq+cbXYslcQTtEBNL9a5FKbeF1qDpwrscWtGThPsbb0QFUMb03FN6yZBP2ujF29J8Fvm89igasxA7F67ohJgUku5ni9qOsMNqm5juexCTGJvzPkyinymGFYz55MUqrySZQPbRxoQU9tcfbOv9AH4xR/3DPe5krqjo3kk5pK6QWpH37rBgQZLmM7TWooyPiRkuc5Wn/1z6rQIzH5rCLqv4C8J16MAwgU1W+KTrHd4t8hIDAQG9vwkL9SYAvlz38HMKL9utu2g4c9jhAJE/H0mePlp+LDrWSgnC+R+nyH91niaUlwv3wsehP0maYCgEsTJn/3vsNouk5VCy4IGGZbkPubuJM6hE8RP0r4='
注:對password
進行了加密處理。
創建一個 APS.NET Core 應用程序(2.0 版本),然后 Nuget 安裝程序包:
> install-package Steeltoe.Extensions.Configuration.ConfigServerCore
在appsettings.json
配置文件中,增加下面配置:
{
"spring": {
"application": {
"name": "xishuai-config" //配置文件名稱
},
"cloud": {
"config": {
"uri": "http://manager1:8180", //指向配置中心地址
"env": "dev" //配置中心profile
}
}
}
}
然后創建一個ConfigServerData
模型:
public class ConfigServerData
{
public Info Info { get; set; }
}
public class Info
{
public string Profile { get; set; }
public string Name { get; set; }
public string Password { get; set; }
}
增加HomeController
訪問:
public class HomeController : Controller
{
private IOptionsSnapshot<ConfigServerData> IConfigServerData { get; set; }
private IConfigurationRoot Config { get; set; }
public HomeController(IConfigurationRoot config, IOptionsSnapshot<ConfigServerData> configServerData)
{
if (configServerData != null)
IConfigServerData = configServerData;
Config = config;
}
public IActionResult Error()
{
return View();
}
public ConfigServerData ConfigServer()
{
var data = IConfigServerData.Value;
return data;
}
public IActionResult Reload()
{
if (Config != null)
{
Config.Reload();
}
return View();
}
}
Startup.cs
中增加配置:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables()
.AddConfigServer(env);
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
// Optional: Adds IConfiguration and IConfigurationRoot to service container
services.AddConfiguration(Configuration);
// Adds the configuration data POCO configured with data returned from the Spring Cloud Config Server
services.Configure<ConfigServerData>(Configuration);
}
}
啟動項目,然后執行命令:
$ curl http://192.168.1.3:5000/home/ConfigServer
{"info":{"profile":"dev","name":"xishuai7","password":"xishuai123"}}
當配置中心數據更新了,可以訪問http://192.168.1.3:5000/home/Reload
進行刷新配置。
ASP.NET 4.x 版本的實現,和上面的類似,這邊就不敘述了,可以查看項目代碼:https://github.com/yuezhongxin/Steeltoe.Samples/tree/master/Configuration/AspDotNet4
參考資料: