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 8081:8080 -d --name eureka -d netflixoss/eureka:1.3.1

运行成功后,如下图所示:

让我们用我们的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":12000000
  },
  "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然后注入给这个服务类,然后再将这个服务类加入DIvar 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":12000000
  },
  "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": 801,
      "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(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
    TimeSpan.FromSeconds(30));

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

都有非常详细的介绍。

原文地址:https://www.cnblogs.com/ck0074451665/p/10347330.html

时间: 2024-08-29 08:33:04

asp.net core microservices 架构之eureka服务发现的相关文章

asp.net core microservices 架构之Task 事务一致性 事件源 详解

一 aspnetcore之task的任务状态-CancellationToken 我有一篇文章讲解了asp.net的线程方面的知识.我们知道.net的针对于多线程的一个亮点就是Task,net clr维护了一个线程池,自动的分派给task执行,执行完成,迅速返回线程池,并且维护异常和状态,针对于基础的thread和其他两种异步编程,Task非常的灵巧,但是针对和应用生命周期关联的异步任务,还是使用Workbackgroup比较合适,或者甚至是基础的thread,因为Task比较高级的线程类,操作

asp.net core microservices 架构之 分布式自动计算(一)

   一:简介   自动计算都是常驻内存的,没有人机交互.我们经常用到的就是console job和sql job了.sqljob有自己的宿主,与数据库产品有很关联,暂时不提.console job使用quartz.net框架,目前3.x已经支持netcore. 如果单台服务器运行计算,那就很简单了,quartz很强大了,而且支持故障灾难转移集群,docker做宿主,很容易实现.但是分布式就不可同日而语了.如果你的一个数据处理太慢,需要多进程多主机处理,那么就需要多进程自动协调处理这一数据,比如

SpringCloud系列四:Eureka 服务发现框架(定义 Eureka 服务端、Eureka 服务信息、Eureka 发现管理、Eureka 安全配置、Eureka-HA(高可用) 机制、Eureka 服务打包部署)

1.概念:Eureka 服务发现框架 2.具体内容 对于服务发现框架可以简单的理解为服务的注册以及使用操作步骤,例如:在 ZooKeeper 组件,这个组件里面已经明确的描述了一个服务的注册以及发现操作流程,在整个 Rest 架构里面,会存在有大量的微服务的信息. 在 SpringCloud 之中使用了大量的 Netflix 的开源项目,而其中 Eureka 就属于 Netflix 提供的发现服务组件,所有的微服务在使用之中全部向 Eureka 之中进行注册,而后客户端直接利用 Eureka 进

ASP.NET Core使用TopShelf部署Windows服务

asp.net core很大的方便了跨平台的开发者,linux的开发者可以使用apache和nginx来做反向代理,windows上可以用IIS进行反向代理. 反向代理可以提供很多特性,固然很好.但是还有复杂性,我们也可以使用windows service来直接启动kestrel. asp.net core官方网站提供了一种基于windows服务部署的方法:在 Windows 服务中托管 ASP.NET Core 这种方式需要修改代码,然后部署的时候,使用命令行创建.安装服务,然后再启动. 感觉

asp.net core 开发的https证书服务-agilelabs.net

创建证书-生成CSR(Certificate Sign Request): 填写证书基本信息 接下来我们就可以看到创建的证书签名请求信息(CSR): 为我们刚才创建的CSR签名: 签名的意思是说通过证书签发机构给我们生成证书, 在刚才的CSR信息链接的部分有Request Sign链接, 点击之后目前会自动签名, 直接返回. 紧接着我们会看到证书信息: 点击Download Certificate下载. 小结: 至此, 我们已经完成了我们证书的申请与签发,下载之后就可以用在我们需要证书的各种测试

微服务架构下的服务发现

编者的话]这是关于使用微服务架构创建应用系列的第四篇文章.第一篇介绍了微服务架构的模式,讨论了使用微服务架构的优缺点.第二和第三篇描述了微服务架构内部的通讯机制.这篇文章中,我们将会探讨服务发现相关问题. 为什么要使用服务发现? 我们设想一下当正在写代码时,使用了提供REST API或者Thrift API的服务,为了完成一次服务请求,代码需要知道服务实例的网络位置(IP地址和端口).传统应用都运行在物理硬件上,服务实例的网络位置都是相对固定的.例如,代码可以从一个经常变更的配置文件中读取网络位

Eureka(服务发现框架)

什么是服务发现,不了解的可以自行百度或googleEureka是netfix开发的一个框架,定位于中间层,用于保障负载均衡和中间层的故障转移,它是基于RESET开发的服务框架基本组件:Eureka Server 和Eureka Client简单框架如下图:Eureka Server:主要提供存放注册的信息,它也提供了web界面可以查看有哪些服务,他的可用性通过复制来实现,可以通过keeplived来实现高可用Eureka Client:是一个Java客户端,放在各个服务中,用于跟server端进

【Eureka篇三】Eureka服务发现(4)

注:该知识点并不是重点. 修改子模块:microservicecloud-provider-dept-8001 1. 修改DeptController @Autowired private org.springframework.cloud.client.discovery.DiscoveryClient client; @RequestMapping(value = "/discovery", method = RequestMethod.GET) public Object dis

asp.net core 2.0 邮件发送服务

网上找了一下,发现一个很不错的邮件发送服务Mailgun,首先要注册Mailgun账号,获得apikey以及domainame: 然后项目中安装nuget: 配置并注册服务: public interface IEmailSender { Task SendEmailAsync(string email, string subject, string message); } public class EmailSender:IEmailSender { private readonly Emai