Net8微服务之Consul、Ocelot、IdentityServer4

前言

情绪的尽头是沉默

1.微服务概念

1.1微服务发展

分布式解决性能问题,微服务解决维护性、扩展性、灵活性。

image-20240422000607835

1.2微服务概念

微服务(或称微服务架构),是一种现代化的软件架构方法,它将一个应用程序分解为多个小型、独立的服务单元,每个服务都负责特定的业务功能,并且可以独立开发、测试、部署和扩展。

这些服务通常是松散耦合的,使用不同的技术栈和开发语言,并通过轻量级通信机制(如Rest API、消息传递 进行交互。微服务架构的核心在于提高应用程序的可维护性、可扩展性和灵活性,同时允许团队成员使用最适合其需求的技术和开发语言。与传统的大型单体应用架构相比,微服务架构能够更好地应对复杂系统和高速变化的技术环境。

特点:

  • 一组小的服务
  • 独立的进程
  • 轻量级的通信
  • 基于业务能力(DDD)
  • 独立部署:迭代速度快
  • 无集中式管理:无须统一技术栈,可以根据不同的服务或者团队进行灵活选择。

1.3微服务架构

微服务架构实施需要从业务领域、服务拆分、服务通信、数据管理、服务治理、自动化部署、监控与日志、测试策略等多个方面进行规划和设计。

image-20240422000831431

1.4微服务技术栈

微服务架构实施需要从业务领域、服务拆分、服务通信、数据管理、服务治理、自动化部署、监控与日志、测试策略等多个方面进行规划和设计。

2.Nginx负载均衡

基于Net8创建一个WebApi服务:Peng.Microservice.ServiceA

image-20240422001745868

在Peng.Microservice.ServiceA下cmd运行服务

dotnet run --urls=http://*:5000 --port=5000
dotnet run --urls=http://*:5001 --port=5001

image-20240422002902110

配置Nginx

同一个服务可以启动多个进程进行访问。

image-20240422002802901

3.Consul服务注册

基本使用概念之前写过:https://www.cnblogs.com/pengboke/p/16118746.html

3.1安装

补充到之前的博客了

https://www.cnblogs.com/pengboke/p/18156610

3.2服务注册

引入包

<PackageReference Include="Consul" Version="1.7.14.3" />

使用

 // Consul
builder.Services.ConsulRegister(option => { 
     var consulConfig = configuration.GetSection("ConsulConfig").Get<ConsulConfig>();
     option.Config(consulConfig);
 });

app.UseConsul(builder.Services.BuildServiceProvider(), app.Lifetime, configuration);

image-20240422215541291

启动

dotnet run --urls=http://*:5001 --port=5001
dotnet run --urls=http://*:5002 --port=5002

Peng.Microservice.ServiceA启动2个实例

image-20240422215305474

查看Consul

image-20240422215456230

3.3服务发现

创建控制台客户端获取ConsulClient注册实例并调用

image-20240422221403557

3.4服务权重

添加权重命令

dotnet run --urls=http://*:5001 --port=5001 --weight=1
dotnet run --urls=http://*:5002 --port=5002 --weight=2

image-20240422221858229

根据权重获取服务实例

因为5002权重大些,调用的几率会高

image-20240422222131625

3.5健康检测

添加健康检测接口,并配置AgentServiceRegistration

image-20240422222334633

Consul显示正常

image-20240422222728829

4.Ocelot网关

4.1概念

常用网关:Kong、Spring Cloud Gateway、Bumblebee、Ocelot

基本概念之前写过,这里不过多赘述:https://www.cnblogs.com/pengboke/p/16118726.html

安装包

  <ItemGroup>
    <PackageReference Include="Ocelot" Version="23.2.2" />
    <PackageReference Include="Ocelot.Provider.Consul" Version="23.2.2" />
    <PackageReference Include="Ocelot.Provider.Polly" Version="23.2.2" />
  </ItemGroup>

4.2Ocelot直连服务

注入服务

image-20240422233947308

配置路由ocelot.json

"Type": "RoundRobin"意思时轮询,每个服务实例都访问一次

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": "5001"
        },
        {
          "Host": "localhost",
          "Port": "5002"
        }
      ],
      "UpstreamHttpMethod": [
        "GET",
        "POST",
        "DELETE",
        "PUT",
        "OPTIONS"
      ],
      "UpstreamPathTemplate": "/ServiceA/{url}", //httn://localhost:端口号/ServiceA/Home/Get
      "LoadBalancerOptions": {
        "Type": "RoundRobin",
        "LeastConnection": "RoundRobin" //"LeastComnection" //少连接数的服务器 "NoLoadBalance”//不负载均衡 /"CookieStickySessions” //会话粘滞 //
      }
    }  
  ]
}

运行

dotnet run --urls=http://*:9000 --port=9000

image-20240422233919488

循环10次,每1s一次,每个服务轮流调用

image-20240423000854510

4.3Ocelot连接Consul

如果Ocelot直连服务实例,当某一个服务实例故障后,程序会无法连接。

所以需要连接Consul,故障后直接下机。

注入AddConsul

image-20240422235705344

修改配置文件

//consul+ocelot
{
  //服务中心信息
  "GlobalConfiguration": {
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "Consul"
    }
  },
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "UpstreamPathTemplate": "/ServiceA/{url}", //httn://localhost:端口号/ServiceA/Home/Get
      "UpstreamHttpMethod": [
        "GET",
        "POST",
        "DELETE",
        "PUT",
        "OPTIONS"
      ],
      "UseServiceDiscovery": true, //使用服务发现
      "ServiceName": "Peng.Microservice.ServiceA", //服务名称
      "LoadBalancerOptions": {
        "Type": "RoundRobin",
        "LeastConnection": "RoundRobin" //"LeastComnection" //少连接数的服务器 "NoLoadBalance”//不负载均衡 /"CookieStickySessions” //会话粘滞 //
      }
    }
  ]
}

当断掉5001,使5001故障,Ocelot不会在来连接5001,一直使用可用的5002。

image-20240422235751946

4.4Ocelot缓存

修改配置,增加FileCacheOptions节点

//consul+ocelot(缓存)
{
  //服务中心信息
  "GlobalConfiguration": {
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "Consul"
    }
  },
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "UpstreamPathTemplate": "/ServiceA/{url}", //httn://localhost:端口号/ServiceA/Home/Get
      "UpstreamHttpMethod": [
        "GET",
        "POST",
        "DELETE",
        "PUT",
        "OPTIONS"
      ],
      "UseServiceDiscovery": true, //使用服务发现
      "ServiceName": "Peng.Microservice.ServiceA", //服务名称
      "LoadBalancerOptions": {
        "Type": "RoundRobin",
        "LeastConnection": "RoundRobin" //"LeastComnection" //少连接数的服务器 "NoLoadBalance”//不负载均衡 /"CookieStickySessions” //会话粘滞 //
      },
      //缓存
      "FileCacheOptions": {
        "TtlSeconds": 10, //缓存时间
        "Region": "ServiceA" //缓存区
      }
    }
  ]
}

循环20次,每2s一次,10s过期会重新请求。

image-20240423001126548

4.5Ocelot自定义缓存

实现 IOcelotCache

image-20240423011245127

注入IOcelotCache服务

image-20240423011306915

改小过期时间,方便测试

image-20240423011337611

测试调用,输出自定义缓存日志

image-20240423011704505

4.6故障场景

1、重试策略(Retry):当服务调用失败时,Polly可以自动进行重试,这有助于 处理那些可能因为暂时性问题导致的服务不可用情况。

2、断路器(Circuit Breaker):当检测到服务连续不可用时,断路器策略会介入,快速返回错误响应,避免对下游服务的持续请求,从而预防服务雪崩现象。

3、超时策略(Timeout):为服务调用设置一个最大执行时间,超过这个时间的服务调用将被认为失败,可以采取预设的应对措施。

4、舱壁隔离(Bulkhead Isolation):通过限制对服务的并发调用数量,防止因某个服务的问题影响到整个系统的稳定性。

5、缓存策略(Cache):提供一种机制,可以在服务调用的结果不变的情况下直接使用缓存结果,减少不必要的服务调用。

6、降级策略(Fallback):当服务调用失败时,可以提供一个备用的逻辑或者数据作为响应,提高用户体验。

7、策略组合(PolicyWrap) : Polly针对不同的故障有不同的策略,我们可以灵活的组合策略,上述的六种策略可以灵活组合使用。

4.7Ocelot限流

配置限流,这里的策略为了方便测试配置策略5分钟最多访问3次。

image-20240423012354884

{
  //服务中心信息
  "GlobalConfiguration": {
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "Consul"
    },
    "RateLimitOptions": {
      "QuotaExceededMessage": "Too many requests!Please wait a moment!", // 当请求过载被截断时返回的消息,中文会出现乱码
      "HttpStatusCode": 503 // 当请求过载被截断时返回的http status
    }
  },
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "UpstreamPathTemplate": "/ServiceA/{url}", //httn://localhost:端口号/ServiceA/Home/Get
      "UpstreamHttpMethod": [
        "GET",
        "POST",
        "DELETE",
        "PUT",
        "OPTIONS"
      ],
      "UseServiceDiscovery": true, //使用服务发现
      "ServiceName": "Peng.Microservice.ServiceA", //服务名称
      "LoadBalancerOptions": {
        "Type": "RoundRobin",
        "LeastConnection": "RoundRobin" //"LeastComnection" //少连接数的服务器 "NoLoadBalance”//不负载均衡 /"CookieStickySessions” //会话粘滞 //
      },
      //缓存
      "FileCacheOptions": {
        "TtlSeconds": 5, //缓存时间
        "Region": "ServiceA" //缓存区
      },
      //限流
      "RateLimitOptions": { //限流,限制了单位时间内的访问量
        "ClientWhitelist": [], //白名单
        "EnableRateLimiting": true,
        "Period": "5m", //1s, 5m, 1h, 1d  
        "PeriodTimespan": 5, //多少秒之后客户端可以重试
        "Limit": 3 //统计时间段内允许的最大请求数量
      }
    }
  ]
}

5分钟最多访问3次,第4次的时候直接返回503,然后5s之后可以再重新请求。

image-20240423012600438

4.8Ocelot+Polly熔断

修改配置文件,需要配置网关IP端口

熔断策略:5s内允许三次错误,5s后可重新请求

image-20240423015032060

//consul+ocelot+polly熔断
{
  //服务中心信息
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:9000",
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "Consul"
    },
    "RateLimitOptions": {
      "QuotaExceededMessage": "Too many requests!Please wait a moment!", // 当请求过载被截断时返回的消息,中文会出现乱码
      "HttpStatusCode": 503 // 当请求过载被截断时返回的http status
    }
  },
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "UpstreamPathTemplate": "/ServiceA/{url}", //httn://localhost:端口号/ServiceA/Home/Get
      "UpstreamHttpMethod": [
        "GET",
        "POST",
        "DELETE",
        "PUT",
        "OPTIONS"
      ],
      "UseServiceDiscovery": true, //使用服务发现
      "ServiceName": "Peng.Microservice.ServiceA", //服务名称
      "LoadBalancerOptions": {
        "Type": "RoundRobin",
        "LeastConnection": "RoundRobin" //"LeastComnection" //少连接数的服务器 "NoLoadBalance”//不负载均衡 /"CookieStickySessions” //会话粘滞 //
      },
      ////缓存
      //"FileCacheOptions": {
      //  "TtlSeconds": 5, //缓存时间
      //  "Region": "ServiceA" //缓存区
      //},
      //限流
      "RateLimitOptions": { //限流,限制了单位时间内的访问量
        "ClientWhitelist": [], //白名单
        "EnableRateLimiting": true,
        "Period": "1s", //1s, 5m, 1h, 1d  
        "PeriodTimespan": 5, //多少秒之后客户端可以重试
        "Limit": 1000 //统计时间段内允许的最大请求数量
      },
      //熔断设置
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3, //允许多少个异常请求
        "DurationOfBreak": 5000, // 熔断的时间5s,单位为ms
        "TimeoutValue": 5000 //单位ms,如果下游请求的处理时间超过多少则自动将请求设置为超时 默认90秒
      }
    }
  ]
}

Peng.Microservice.ServiceA添加一个主动抛出异常的接口

image-20240423015144290

注入Polly

image-20240423015233742

5s内出现3次异常,第4次503,5s内都是503,然后5s过后可以重新请求。

image-20240423015322301

4.9Polly服务降级

安装包

  <ItemGroup>
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

\Peng.Microservice.ServiceA添加接口GetExceptionByPolly,使用Policy进行降级,模拟当调用别的服务异常时返回Server Error

image-20240423173017430

客户端调用

image-20240423173219543

5.认证授权

5.1概念

以前简单的写过一些IdentityServer4:

https://www.cnblogs.com/pengboke/p/15738842.html

客户端模式:客户端模式只对客户端进行授权,不涉及到用户信息。如果你的api需要提供到第三方应用,第三方应用自己做用户授权,不需要用到你的用户资源,就可以用客户端模式,只对客户端进行授权访问api资源。

密码模式:需要客户端提供用户名和密码,密码模式相较于客户端凭证模式。通过User的用户名和密码向Identity Server申请访问令牌。

**(简化 没有授权码这个中间步骤,所以称为(授权码)"隐藏式"(implicit)。

授权码模式:授权码模式隐藏码模式最大不同是授权码模式不直接返回token,而是先返回一个授权码,然后再根据这个授权码去请求token。这比隐藏模式更为安全。从应用场景上来区分的话,隐藏模式适应于全前端的应用,授权码模式适用于有后端的应用,因为客户端根据授权码去请求token时是需要把客户端密码转进来的,为了避免客户端密码被暴露,所以请求token这个过程需要放在后台。

5.2授权服务

创建授权服务,并安装IdentityServer4

<PackageReference Include="IdentityServer4" Version="4.1.2" />

image-20240423203009624

配置ids4

 /// <summary>
 /// 授权配置
 /// </summary>
 public class AuthConfig
 {
     /// <summary>
     /// 定义ApiResource
     /// 这里的资源(Resources)指的就是管理的API
     /// </summary>
     /// <returns>多个ApiResource</returns>
     public static IEnumerable<ApiResource> GetApiResources()
     {
         return new[]
         {
             new ApiResource("ServiceA", "服务A")
             {
                 Scopes={ "scope1" }//4.x必须写的
             }
         };
     }

     /// <summary>
     /// 作用范围
     /// </summary>
     public static IEnumerable<ApiScope> GetApiScopes()
     {
         return new ApiScope[]
           {
             new ApiScope("scope1"),
             new ApiScope("scope2"),
           };
     }

     /// <summary>
     /// 定义验证条件的Client
     /// </summary>
     /// <returns></returns>
     public static IEnumerable<Client> GetClients()
     {
         return new[]
         {
             new Client
             {
                 ClientId = "AuthCenter",//客户端唯一标识
                 ClientName="AuthenticationCenter",//客户端名称
                 ClientSecrets = new [] { new Secret("123456".Sha256()) },//客户端密码,进行了加密
                 AllowedGrantTypes = GrantTypes.ClientCredentials,
                 //授权方式,客户端认证,只要ClientId+ClientSecrets
                 AllowedScopes = new [] { "scope1" },//允许访问的资源

                 Claims=new List<ClientClaim>(){
                     new ClientClaim(IdentityModel.JwtClaimTypes.Role,"Admin"),
                     new ClientClaim(IdentityModel.JwtClaimTypes.NickName,"Admin"),
                 }
             }
         };
     }
 }

注入id4服务

image-20240423203156629

运行授权服务

dotnet run --urls=http://*:9100 --port=9100

image-20240423203707474

访问获取jwt

image-20240423205347672

5.3JWT

JWT全称Json Web Token

把请求的Token放到https://jwt.io/

首先可以看到Token由Header(头部)、Payload(载荷)、Signature(签名)组成

然后看Payload发现获取的资源就是我们AuthConfig配置的

image-20240423205641485

5.4.Ocelot配置id4

Peng.Microservice.GateWay网关服务Ocelot给API服务配置id4认证

image-20240423214444407

Authority:认证服务地址

image-20240423214551535

Ocelot配置id4路由

image-20240423214802505

{
  "DownstreamPathTemplate": "/connect/token",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "localhost",
      "Port": 9100
    }
  ],
  "UpstreamPathTemplate": "/connect/token",
  "UpstreamHttpMethod": [ "Post" ]
},
{
  "DownstreamPathTemplate": "/connect/authorize",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "localhost",
      "Port": 9100
    }
  ],
  "UpstreamPathTemplate": "/connect/authorize",
  "UpstreamHttpMethod": [ "Get" ]
},
{
  "DownstreamPathTemplate": "/connect/logout",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "localhost",
      "Port": 9100
    }
  ],
  "UpstreamPathTemplate": "/connect/logout",
  "UpstreamHttpMethod": [ "Get" ]
}

运行3个服务

# 网关服务
dotnet run --urls=http://*:9000 --port=9000
# 授权服务
dotnet run --urls=http://*:9100 --port=9100
# 服务A
dotnet run --urls=http://*:5001 --port=5001

image-20240423211309284

直接访问Api资源401

image-20240423215113250

通过Ocelot网关请求Token,带上Token再访问Api
image-20240423215430862

5.5授权角色

ocelot.json配置角色,只有Admin角色才可以访问

AuthConfig配置了客户端角色为Admin

image-20240424230825153

所以请求到Token可以正常访问接口

image-20240424231053638

修改配置的角色,id4客户端没有配置该角色权限,所以返回Forbidden(403)

image-20240424231231200

posted @ 2024-04-24 23:41  peng_boke  阅读(1801)  评论(0)    收藏  举报