asp.net core microservices 架构之eureka服务发现
一 简介
微服务将需多的功能拆分为许多的轻量级的子应用,这些子应用相互调度。好处就是轻量级,完全符合了敏捷开发的精神。我们知道ut(单元测试),不仅仅提高我们的程序的健壮性,而且可以强制将类和方法的设计尽量的单一化。那么微服务也是这样,敏捷对于软件工程的意义就是快速开发,验证市场需求,然后快速改进,从而适应市场节奏。什么东西要快速,就必须轻量级。大家知道一个应用的复杂程度,完全是和这个项目的功能和代码数量挂钩的,这是软件自诞生就存在的问题,一个设计不好的软件,最后会让这个软件更新和改进变的非常复杂,直至没有人敢去碰这个应用,我一直认为这个代码量和复杂程度挂钩,困难程度是以指数的量增加的,而不仅仅是线性增加。这就需要一个好的设计去解决问题,一个微服务尽量的单一,与其他子应用几乎没有代码上的关联,所以可以快速出原型,快速开发,验证市场,也可以快速砍掉一个项目,而不影响其他的应用。
当然,因为微服务有他的局限性,所以也有它的坏处,比如一致性会打折扣,对于一致性的问题,我前几篇文章已经做过探讨。还有就是虽然软件开发部署工作解脱了,但是您想,原来一个应用,现在三四个应用进行协调和通讯,对于这个分布式架构的要求就会高,如何把他们打散又要弱关联在一起,那么eureka诞生了。asp.net core支持一个底层的库,Microsoft.Extensions.Http.Polly,这个库是表达策略,例如以流畅且线程安全的方式处理重试、断路器、超时、Bulkhead 隔离和回退,就是防止雪崩,熔断降级等特性。感兴趣的可以看asp.net core 官方文档: https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2#use-polly-based-handlers 。多说一句,asp.net core也有后台服务job的底层api,有兴趣的可以试着做出一套asp.net core的job框架。甚至服务发现,配合zookeeper,也可以开发出一套属于asp.net core的框架。
言归正传,这里还需要注意的是一点是,一个微服务是可以和以前的比如面向传统服务类型的应用共存的,如果公司内部可以提出一个应用作为微服务来设计,那么我恭喜你,从泥潭中跨出了一步,如果你们公司全部用微服务设计了,那么真的恭喜,完全跳出了泥潭。当然一些重量级的应用,因为必须使用分布式事务等等的特殊要求,还是可以存在,微服务还是需要根据实际情况来实施的。
二 eureka集成
说到eureka前,我们需要明白一个术语:backing service。我把他翻译为协助服务,或者帮助服务。主要意思就是对资源具有管理,丢失处理,连接和配置等功能的一个程序。那微服务资源自然就是我们各种各样的服务,如图所示:
当然除过eureka,还有etcd,Consul,Marathon,ZooKeeper可以供大家挑选。
使用docker运行eureka服务器端:
docker run -p : -d --name eureka \
-d netflixoss/eureka:1.3.
运行成功后,如下图所示:
让我们用我们的Walt.Framework.OrderService项目定义一个api接口和将配置eureka客户端,然后至今运行,就会直接将实例添加进eureka服务端:
设计api,我们直接看生成的api描述,使用swagger生成的api描述:
再安装eureka客户端,首先查找都有那些包:
nuget.exe list eureka
显示结果,红框中的包就是文档中要求针对netcore的包:
客户端需要引入包:
dotnet add Walt.TestMcroServices.Webapi.csproj package Steeltoe.Discovery.ClientCore
然后再注册服务,这个大家都应该熟悉的不能再熟悉了,因为我们开发自定义的服务已经有三个了:
public class Startup {
...
public IConfiguration Configuration { get; private set; }
public Startup(...)
{
...
}
public void ConfigureServices(IServiceCollection services)
{
// Add Steeltoe Discovery Client service
services.AddDiscoveryClient(Configuration); //添加服务 // Add framework services.
services.AddMvc();
...
}
public void Configure(IApplicationBuilder app, ...)
{
...
app.UseStaticFiles();
app.UseMvc(); // Use the Steeltoe Discovery Client service
app.UseDiscoveryClient();
//这里是将服务应用到http通道,我们知道这里处理的都是asp.net core 相关请求的http通道的一些事情,类似与asp.net的那几个application事件。
}
这里多说一句关于owin的事情,上面代码的中间件技术和OWIN完全不同,OWIN:开放 Web 接口,它定义了在管道中使用中间件来处理请求和相关响应的标准方法。我们看看asp.net core 的管道都干些什么?如图所示:
官方说辞:
所以无论各个环节都是处理http上下文中的内容,web驱动监听到http请求和发送请求的内容,就是request,和response,在这两个之间就是我们的通道,不管是处理生成http内容时,还是身份验证,session处理,都是这个通道之间的某个环节。
那owin作用是什么尼?就是定义这些中间环节的一些标准,所以任何web框架,只要实现了owin接口标准,两个不同web框架,就都可以相互兼容。
言归正准,继续eureka的客户配置, 配置文件:
{
"Logging": {
"LogLevel": {
"Default": "trace",
"System": "trace",
"Microsoft": "trace",
"Steeltoe": "Debug"
},
"KafkaLog":{
"Prix":"这是我的自定义日志提供程序",
"LogStoreTopic":"mylog-orderservice"
}
},
"KafkaService":{
"Properties":{
"bootstrap.servers":"192.168.249.106:9092",
"group.id":"group1"
}
},
"zookeeperService":{
"Connectstring":"192.168.249.106:2181",
"SessionTimeout":
},
"spring": {
"application": {
"name": "orderservice"
}
},
"eureka": {
"client": {
"serviceUrl": "http://192.168.249.105:8080/eureka/v2/",
"shouldFetchRegistry": false
},
"instance": {
"ipAddress":"192.168.249.102",
"preferIpAddress":true,
"port": 802,
"instanceId":"orderserviceinstance"
}
}
}
红颜色的就是eureka需要使用的配直节。
所以在startup中的配置就需要把整个configuration传进去,让他自己查找,而不用精确找到configuration配直节后,再传入服务构建,这个非常简单,总共就两行代码。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Steeltoe.Discovery.Client;
using Swashbuckle.AspNetCore.Swagger; namespace Walt.TestMicroservices.OrderService
{
public class Startup
{
public Startup(IConfiguration configuration
,IHostingEnvironment hostingEn
, ILoggerFactory loggerFac )
{
Configuration = configuration;
HostingEn = hostingEn;
LoggerFac = loggerFac;
} public IConfiguration Configuration { get; } public IHostingEnvironment HostingEn { get; } public ILoggerFactory LoggerFac { get; set; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(mvcOptions=>{ }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// services.AddAuthorization();
// services.AddAuthentication("Bearer")
// .AddIdentityServerAuthentication(options =>
// {
// options.Authority = "http://localhost:64433";
// options.RequireHttpsMetadata = false;
// options.ApiName = "api1";
// });
// Add Steeltoe Discovery Client service
services.AddDiscoveryClient(Configuration);
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
});
var log = LoggerFac.CreateLogger<Startup>();
log.LogDebug("服务配置完成");
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{ var log = LoggerFac.CreateLogger<Startup>();
log.LogInformation("infomation");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseDiscoveryClient();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.RoutePrefix = string.Empty;
});
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "api/{controller=Home}/{action=Index}/{id?}");
}); app.UseAuthentication();
log.LogDebug("通道配置完毕");
}
}
}
运行:
我们看到注册成功了,那看调用方:Walt.TestMicroServices.Webapi
startup类中注册:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Walt.Framework.Service;
using Walt.Framework.Configuration;
using Walt.Framework.Service.Kafka;
using Steeltoe.Discovery.Client;
using System;
using Steeltoe.Common.Http.Discovery; namespace Walt.TestMicroServoces.Webapi
{
public class Startup
{
public Startup(IConfiguration configuration
,IHostingEnvironment hostingEn
, ILoggerFactory loggerFac )
{
Configuration = configuration;
HostingEn = hostingEn;
LoggerFac = loggerFac;
} public IConfiguration Configuration { get; } public IHostingEnvironment HostingEn { get; } public ILoggerFactory LoggerFac { get; set; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IKafkaService, KafkaService>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAuthorization();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:64433";
options.RequireHttpsMetadata = false; options.ApiName = "api1";
}); services.AddKafka(KafkaBuilder =>
{
var kafkaConfig = Configuration.GetSection("KafkaService");
KafkaBuilder.AddConfiguration(kafkaConfig);
}); //services.AddSingleton<IOrderService, OrderService>();
// Add Steeltoe Discovery Client service
services.AddDiscoveryClient(Configuration); // Add Steeltoe handler to container
services.AddTransient<DiscoveryHttpMessageHandler>(); // Configure a HttpClient
services.AddHttpClient<OrderService>(c =>
{
c.BaseAddress = new Uri("http://orderservice");
})
.AddHttpMessageHandler<DiscoveryHttpMessageHandler>() //这个就是拦截http请求,然后让发现服务处理这个http请求,而不适用默认的http请求处理程序
.AddTypedClient<IOrderService, OrderService>(); //将上面DiscoveryHttpMessageHandler这个处理程序生成httpclient然后注入给这个服务类,然后再将这个服务类加入DI
var log = LoggerFac.CreateLogger<Startup>();
log.LogDebug("服务配置完成");
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{ var log= LoggerFac.CreateLogger<Startup>();
log.LogInformation("infomation"); if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseMvc();
app.UseDiscoveryClient();
app.UseAuthentication(); log.LogDebug("通道配置完毕");
}
}
}
这里看配置文件:
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Debug",
"Microsoft": "Debug"
},
"KafkaLog":{
"Prix":"这是我的自定义日志提供程序",
"LogStoreTopic":"mylog-webapi"
}
},
"KafkaService":{
"Properties":{
"bootstrap.servers":"192.168.249.106:9092",
"group.id":"group1"
}
},
"zookeeperService":{
"Connectstring":"192.168.249.106:2181",
"SessionTimeout":
},
"spring": {
"application": {
"name": "webapi"
}
},
"eureka": {
"client": {
"serviceUrl": "http://192.168.249.105:8080/eureka/v2/",
"shouldRegisterWithEureka": true
},
"instance": {
"ipAddress":"192.168.249.102",
"preferIpAddress":true,
"port": ,
"instanceId":"webapiinstance"
}
}
}
看调用类,很简单,因为asp.net core和eueka的集成已经在上一步骤中的startup中处理,这里直接使用:
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Steeltoe.Common.Discovery; namespace Walt.TestMicroServoces.Webapi
{
public class OrderService:IOrderService
{
private IConfiguration _config; private HttpClient _httpClient; public OrderService(IConfiguration config
,HttpClient httpClient)
{
_config=config;
_httpClient = httpClient;
}
public Task<string> GetOrder()
{
var task=_httpClient.GetStringAsync("Order");
return task;
}
}
}
调用:
首先看日志:
只要获取到这个实例,就没什么问题了。
页面结果:
注意:我在用nuget包的时候,总是获取不到实例,不知道什么,后来没办法就用源码:
直接就可以了,就算不可以,调式源码,很快也就解决了,看来坑都怕源码,尤其是这种还没大规模使用和讨论的小项目,所以我这次的代码就把这个引用保留,大家下载后需要自己下载 Descover源码,然后引用这个工程就ok了。
Discovery github地址:https://github.com/SteeltoeOSS/Discovery
三 集成polly
polly 提供了微服务之间调用的容错功能,无论是慢超市,还是失败,对于微服务之间提供了很多策略,如下的策略:
Policy | Premise | Aka | How does the policy mitigate? |
---|---|---|---|
Retry (policy family) (quickstart ; deep) |
Many faults are transient and may self-correct after a short delay. 重试 |
"Maybe it's just a blip" | Allows configuring automatic retries. |
Circuit-breaker (policy family) (quickstart ; deep) |
When a system is seriously struggling, failing fast is better than making users/callers wait. 失败而不是调用等待 Protecting a faulting system from overload can help it recover. |
"Stop doing it if it hurts"
"Give that system a break" |
Breaks the circuit (blocks executions) for a period, when faults exceed some pre-configured threshold. |
Timeout (quickstart ; deep) |
Beyond a certain wait, a success result is unlikely. 超时 |
"Don't wait forever" | Guarantees the caller won't have to wait beyond the timeout. |
Bulkhead Isolation (quickstart ; deep) |
When a process faults, multiple failing calls backing up can easily swamp resource (eg threads/CPU) in a host. A faulting downstream system can also cause 'backed-up' failing calls upstream. Both risk a faulting process bringing down a wider system. 一个进程失败或多个失败的调用可以很容易的淹没主机的资源。 所以需要隔离墙。 |
"One fault shouldn't sink the whole ship" | Constrains the governed actions to a fixed-size resource pool, isolating their potential to affect others. |
Cache (quickstart ; deep) |
Some proportion of requests may be similar. | "You've asked that one before" | Provides a response from cache if known.
Stores responses automatically in cache, when first retrieved. |
Fallback (quickstart ; deep) |
Things will still fail - plan what you will do when that happens. 某些将仍然失败,在它发生的时候,你要有计划准备做一些事。 |
"Degrade gracefully" | Defines an alternative value to be returned (or action to be executed) on failure. |
PolicyWrap (quickstart ; deep) |
Different faults require different strategies; resilience means using a combination. 不同的失败请求有不同的情况,所以可以对上面的策略有不同的结合处理。 |
"Defence in depth" | Allows any of the above policies to be combined flexibly. |
每个策略大家有兴趣试着做例子。
代码中开发非常简单,提供了三种配置策略的方法,下面是其中之一:
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds());
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds()); services.AddHttpClient("conditionalpolicy")
// Run some code to select a policy based on the request
.AddPolicyHandler(request =>
request.Method == HttpMethod.Get ? timeout : longTimeout);
这个在官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2#use-polly-based-handlers
讲解的非常详细。
还有就是polly的github地址:https://github.com/App-vNext/Polly
都有非常详细的介绍。
asp.net core microservices 架构之eureka服务发现的更多相关文章
- asp.net core系列 61 Ocelot 构建服务发现简单示例
一.概述 Ocelot允许指定服务发现提供程序,如Consul或Eureka. 这二个中间件是用来实现:服务治理或秒服务发现,服务发现查找Ocelot正在转发请求的下游服务的主机和端口.目前Ocelo ...
- asp.net core microservices 架构之Task 事务一致性 事件源 详解
一 aspnetcore之task的任务状态-CancellationToken 我有一篇文章讲解了asp.net的线程方面的知识.我们知道.net的针对于多线程的一个亮点就是Task,net clr ...
- asp.net core microservices 架构之 分布式自动计算(二)
一 简介 上一篇介绍了zookeeper如何进行分布式协调,这次主要讲解quartz使用zookeeper进行分布式计算,因为上一篇只是讲解原理,而这次实际使用, ...
- asp.net core microservices 架构之分布式自动计算(三)-kafka日志同步至elasticsearch和kibana展示
一 kafka consumer准备 前面的章节进行了分布式job的自动计算的概念讲解以及实践.上次分布式日志说过日志写进kafka,是需要进行处理,以便合理的进行展示,分布式日志的量和我们对日志的重 ...
- asp.net core microservices 架构之 分布式自动计算(一)
一:简介 自动计算都是常驻内存的,没有人机交互.我们经常用到的就是console job和sql job了.sqljob有自己的宿主,与数据库产品有很关联,暂时不提.console job使 ...
- .net core microservices 架构之 分布式
.net core microservices 架构之 分布式 一:简介 自动计算都是常驻内存的,没有人机交互.我们经常用到的就是console job和sql job了.sqljob有自己的宿 ...
- 用ASP.NET Core构建可检测的高可用服务--学习笔记
摘要 随着现代化微服务架构的发展,系统故障的定位与快速恢复面临着诸多挑战,构建可检测的服务,帮助线上保障团队时刻掌控应用的运行状况越来越重要.本次分享会讲解如何让 ASP .NET Core 应用与现 ...
- ASP.NET Core基于K8S的微服务电商案例实践--学习笔记
摘要 一个完整的电商项目微服务的实践过程,从选型.业务设计.架构设计到开发过程管理.以及上线运维的完整过程总结与剖析. 讲师介绍 产品需求介绍 纯线上商城 线上线下一体化 跨行业 跨商业模式 从0开始 ...
- 使用 ASP.NET Core 3.1 的微服务开发指南
使用 ASP.NET Core 3.1 的微服务 – 终极详细指南 https://procodeguide.com/programming/microservices-asp-net-core/ A ...
随机推荐
- CROS跨域 解决方案 之 tomcat 做过滤处理解决
摘自:http://www.cnblogs.com/liuwenhao-1/articles/6963540.html 1 .在项目中常常遇到本地访问服务器上的链接数据访问不到,并出现如下问题: 这是 ...
- What is CRC and how does it works?
What is CRC and how does it works? CRC errors refer to Layer 1 or 2 issues. Two things you should ch ...
- 如何防止通过URL地址栏直接访问页面
如何防止通过URL地址栏直接访问页面 一.解决方案 1,将所有页面放在WEB-INF目录下 WEB-INF是Java的web应用安全目录,只对服务端开放,对客户端是不可见的.所以我们可以把除首页(in ...
- CSS气泡提示框 可自定义配置箭头
在线演示 本地下载
- spark学习14(spark local模式运行spark程序的报错)
报错1 java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries. 解 ...
- 为什么Kubernetes不使用libnetwork
Kubernetes 在 1.0 版本之前就已经有了最初的网络插件.与此同时 Docker 也引入了 libnetwork 和 Container Network Model (CNM).现在 Doc ...
- LeetCode第[7]题(Java):Reverse Integer 标签:数学
题目:Reverse Integer 难度:Easy 题目内容: Given a 32-bit signed integer, reverse digits of an integer. Note:A ...
- Android源码下载和编译过程
这是我在编译android源码时整理记录的编译步骤和错误解决方法,期间参考了一些网上的博客和教程. 第一步: 安装ubuntu12.04,分配一盘空间50G,2G内存.如果分配1G内存编译时将报错.( ...
- js的callee和caller方法
转载:http://www.css88.com/archives/1706 http://www.jb51.net/article/25561.htm 这里我们可以知道: caller的使用方法: f ...
- scrapy框架解读--深入理解爬虫原理
scrapy框架结构图: 组成部分介绍: Scrapy Engine: 负责组件之间数据的流转,当某个动作发生时触发事件 Scheduler: 接收requests,并把他们入队,以便后续的调度 Do ...