走进SpringCloud微服务

news2024/11/16 19:48:06

微服务概述

    • 一、注册中心:Eureka ⭐⭐⭐
      • 1.1 原理
      • 1.2 代码
    • 二、负载均衡:Ribbon ⭐
    • 三、远程调用:Feigh ⭐⭐⭐
      • 3.1 原理
      • 3.2 代码
    • 四、熔断限流:Hystrix ⭐⭐⭐
      • 4.1线程池策略
      • 4.2 信号量隔离策略
      • 4.3 方法降级
      • 4.4 断路器、熔断器
    • 五、网关:Getway ⭐⭐⭐
      • 5.1 动态路由
      • 5.2 限流
    • 六、链路追踪:Flueth、Zipkin(docker配置组件) ⭐⭐

1,什么是微服务?

简而言之,微服务架构风格是一种将单个应用程序开发为一组小服务的方法,每个小服务都在自己的进程中运行,并与轻量级机制(通常是 HTTP 资源 API)进行通信。这些服务是围绕业务能力构建的,并且可以通过完全自动化的部署机制独立部署。这些服务的集中管理极少,可以用不同的编程语言编写并使用不同的数据存储技术。

2,微服务架构思想,没有一个落地的技术栈去做支持,此时,SpringCloud就是一个微服务架构落地技术栈,注意:Springcloud是解决接服务问题的系列技术栈。
.

3,SpringCloud家族常用组件:[已忽略]不计

注册中心:Eureka
配置中心: Config (忽略)
远程调用:Feigh
负载均衡:Ribbon
熔断降级:Hystrix
网关:Zuul(忽略)、Getway
消息总线、链路追踪:Slueth、Zipkin

接下来,将要介绍的是Eureka、Feigh、Ribbon、Hystrix、Getway、Slueth
注意:Config作为统一管理项目的配置文件,简单了解一下即可,本文忽略、实际企业开发中采用的springcloud alibaba的nacos统一注册中心和配置中心。
官网中Zuul网关由于停止维护,采用springcloud自家开发的新的网关技术Getway,实际企业应用中,getway基本替代zuul、所以,这里zuul就不做了解,直接学最新技术

.

赋gitee源码练习:https://gitee.com/xzq25_com/springcloud-tets

一、注册中心:Eureka ⭐⭐⭐

1.1 原理

简单概括就是服务注册与发现提供了一个服务注册中心、服务发现的客户端,还有一个方便查看所有注册的服务的界面。所有的服务使用Eureka的服务发现客户端来将自己注册到Eureka的服务器上。

玩的就是心跳!!!!如图所示:
在这里插入图片描述
Eureka的架构图:
在这里插入图片描述
在这里插入图片描述

Eureka由两个组件组成: Eureka服务器和Eureka客户端。

Eureka Server提供服务注册服务
各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

EurekaClient通过注册中心进行访问 它是一个Java客户端,用于简化Eureka
Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka
Server发送心跳(默认周期为30秒)。如果Eureka
Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)。

在微服务项目中,不使用注册中心的现存问题?

举个例子,服务A调用服务B,此时不使用注册中心,则存在需要在服务A中写死服务B的地址信息,如果服务B地址信息发生的改变,则所有调用服务B的服务都需要修改调用B的代码,这种无疑是不可行的。
注册中心Eureka争对上述问题,提供了解决方案::让服务的提供者将信息统一注册到Eureka上(服务名-ip-port),调用者直接从eureka上拉取注册服务列表,直接进行访问,这样效率大大提升

关于Eureka:

1.服务注册端核心启动类上导入@EurekaClient 注解 ok
2.Eureka 作为注册,本身不安全,需要在导入 security 依赖并且配置 yml 文件, 登录时候带上账号、密码
3.EurekaClient 默认 30s 向 service 发送心跳请求,说明自身的存活状态,同时同步注册表中信息。
4.EurekaService 发现 90 秒 client 没有发送心跳请求,则认为 client 宕机
5.EurekaClient 拉取 service 信息到本地缓存,提高访问其他服务的效率
6.EurekaService 在 15min 内,如果超过 85%心跳不正常,依旧对外服务,但是会不删除、添加服务,等到心跳正常,在去其他 service 同步。
7.Eureka 基于 AP 原则,而 Nacos 基于 AP 和 CP 之间横跳

8.Eureka的集群模式中注册中心信息都是互相拉取,是平等的关系,不存在主从关系

1.2 代码

Eureka搭建server服务器,其他服务需要用到Eureka,则导入EurekaClient依赖+注解就可

搭建Eureka-server服务
1,导入依赖

       <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
       </dependency>

2,启动类上添加注解

@EnableEurekaServer

3, application.yml配置文件配置Eureka

eureka:
  client:
    service-url:
      defaultZone: http://eureka8762.com:8762/eureka/    # 将自己配置到其它所有eureka服务上
    register-with-eureka: false  #不向注册中心注册自己
    fetch-registry: false  #自己是注册中心,不用获取注册表
  server:
    enable-self-preservation: true  # 开启自我保护机制
    eviction-interval-timer-in-ms: 60000
  instance:
    hostname: eureka8761.com

server:
  port: 8761    # 指定端口号

spring:
  application:
    name: eureka-server    # 指定EurekaServer的服务名
 

同理创建另外Eureka服务,相同配置,端口号不同即可,此在,这里创建两个客户端服务serve1、serve2注册到注册中心
注意:由于配置了集群,这里需要ip和域名映射,如果使用域名,两台eurekaserve服务同ip部署集群下,配置文件中使用ip:port配置可以会失效,这里需要到本地C盘下:C:\Windows\System32\drivers\etc 的host文件中加上如下所示:

127.0.0.1 eureka8761.com
127.0.0.1 eureka8762.com

在这里插入图片描述

配置客户端Serve1服务
1,导入依赖

   <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

2,添加注解

@EnableEurekaClient

3, application.yml配置文件配置Eureka

eureka:
  client:
    service-url:
      defaultZone:  http://eureka8761.com:8761/eureka/ , http://eureka8762.com:8762/eureka/       # 注册的Eureka服务地址
    registry-fetch-interval-seconds: 30
  instance:
    appname: serve1

同理创建另客户端serve2服务,相同配置,端口不同即可

微服务项目搭建完场之后,启动Eureka集群,启动两个客户端Serve1,Serve2
在这里插入图片描述
去往第一个注册中心:8761端口
在这里插入图片描述

去往第二个注册中心:8761端口
在这里插入图片描述

Eureka的自我保护机制:EurekaService 在 15min 内,如果超过 85%心跳不正常,依旧对外服务,但是会不删除、添加服务,等到心跳正常,在去其他 service 同步。
在这里插入图片描述
至此,注册中心就算搭建起来了!!!
.

二、负载均衡:Ribbon ⭐

Ribbon简单来说:就是当前微服务模块集群的时候,需要负载均衡,就用Ribbon,使用也简单,导入依赖,远程调用方法上加注解@LoadBalanced。
Ribbon也可以不导入依赖, spring-cloud-starter-netflix-eureka-client已经引入了Ribbon,注册中心轮询服务就是用的Ribbon的负载均衡的轮询策略,可以不手动导入依赖
在后续要学习的远程调用Feigh中也自动集成了Ribbon,所以这个可以不用,后续的远程调用在配置文件配置一下即可,注解也自动加上了

三、远程调用:Feigh ⭐⭐⭐

3.1 原理

在开发中,我们常用httpClient去远程调用其他系统的接口,需要我们指定调用的url,Feign 是一个声明式的 Web Service 客户端,它实现了一套远程调用的方法,调用的方式也更为优雅。

使用前提:被调用的模块注册到eureka中,能正常运行!!!

关于Feign

1.Feigin 默认支持 ribbon 做负载均衡
2.在调用方服务启动类上加入注解@EnableFeignClients
3.声明接口,接口映射被调用方 Controller 层的方法,这里时本质采用 jdk 动态代理生成代理对象,调用远程方法
4.在声明的接口上加入注解@FeignClient(value=指定服务名)
5.feign 的 fallback 实际是整合 hystrix,需要在 yml 文件中配置 hystrix
6.单独使用 feign 的 fallback 无法获取异常,需要实现 fallbackfactory接口
7.默认情况下,feign 的超时时间是 1s,hystrix 的线程池隔离的超时时间也是1S

关于feigh负载均衡:配置一下即可

feign:
  hystrix:
    enabled: true

3.2 代码

在调用者服务中使用,创建一个接口,映射服务提供者的controller中的方法
例如:这里Serve2服务,调用Serve1服务,则:接口中的方法则是serve1中controller层的方法,去掉了方法体
在这里插入图片描述
1,服务调用方导入依赖:

 <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-openfeign</artifactId>
 </dependency>

2,创建接口映射,添加注解:@FeignClient

3,Feigh支持降级方法

Feigh还支持方法降级:当服务提供方崩了、资源紧张或者响应速度特备慢的时候,可以走服务调用方设置的降级方法,快速失败,返回托底数据
举例:在淘宝中双11中访问某一件爆款商品,加入购入车的时候,出现了访问时间过久,重新访问一次的页面,此时就是设置了降级方法,因为服务访问人数过多,直接返回另外一个结果。
Feigh的降级方法本质上是整合了后续要学习的Hystrix,这里了解一下即可,后续学习中在说。

注意,fallback不能拿到降级的异常,需要通过FallbackFactory来实现
在这里插入图片描述
在这里插入图片描述

四、熔断限流:Hystrix ⭐⭐⭐

Hystrix总结是实现三个方向:服务降级、熔断、限流

当微服务中某一个服务出现资源紧张、服务崩了,此时由于微服务中是互相调用关系居多,此时可能出现下面一种情况,整个服务都资源紧张了,这中情况是不可取的。
在这里插入图片描述
Hystrix提供了三种策略还解决上述的服务雪崩问题

  • Hystrix提供了线程隔离策略
  • Hystrix提供了方法的降级,可以实现快速失败,返回托底数据
  • Hystrix提供了断路器、熔断器。(摸电门)
  • Hystrix还提供了一个近乎实时的图形化界面,可以查看近期服务的执行情况。

接下来就是分别学习了解一下这三种策略

4.1线程池策略

  • 客户端发送请求到服务时,由容器的线程池中的线程处理请求,执行业务逻辑代码时,采用Hystrix提供的线程池中的线程处理
  • 涉及到了线程的切换时:
    – 由于切换了线程,支持超时时间的设置
    – 由于切换了线程,导致这个请求的处理速度相对更慢
    – 一般比较复杂的业务推荐使用线程池隔离策略

总结:请求交给spring容器线程,处理业务逻辑交给Hystrix线程,这样可以设置超时时间,快速失败!
.

4.2 信号量隔离策略

  • 信号量就是一个计数器,客户端发送请求和业务的处理都使用容器的线程池中的线程处理
  • 通过这个计数器,确认线程池中的情况,给予快速的反馈
  • 没有涉及到线程的切换:
    • 不支持超时时间,无法实现快速失败,返回托底数据
    • 更适合应用到一些处理速度较快的业务上

总结:请求和业务线程都交给spring容器线程处理,无法设置超时时间,适合用在处理速度快的业务上。

示例:
1,导入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2,启动类上加注解:

@EnableCircuitBreaker

3,方法上@HystrixCommand()进行系列配置!

具体配置方案,查看Hystrix在github上的Wiki百科

@HystrixCommand(commandProperties = {
    // 设置隔离策略,THREAD代表线程池隔离,SEMAPHORE代表信号量隔离
    @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD、SEMAPHORE"),
    // 设置超时时间,默认为1s
    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"),
    // 超时时间开关,默认开启
    @HystrixProperty(name = "execution.timeout.enabled", value = "false"),
    // 超时后,是否中断线程,默认为true
    @HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
    // 取消任务后,是否中断线程,默认为false
    @HystrixProperty(name = "execution.isolation.thread.interruptOnCancel", value = "false"),
    // 信号量最大请求并发数,默认值为10,10理论上可以处理25000的每秒请求数
    @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),
})

.

4.3 方法降级

针对目标方法设置降级方法,当目标方法出现问题时,会直接快速失败,执行降级方法,返回托底数据 降级方法的描述要和原方法一模一样

示例:

@HystrixCommand(fallbackMethod = "coreFallback"})
public String core() throws InterruptedException {
    System.out.println("当前线程名为:" + Thread.currentThread().getName());
    return "ok!";
}

public String coreFallback(){
    return "服务器挤爆了,请稍后再试!";
}

4.4 断路器、熔断器

断路器是马丁福勒提出的一个思想Hystrix断路器的执行原理、流程 如下图所示:
在这里插入图片描述断路器默认开启,为了更好的查看效果,配置图形化界面

示例:图形化界面
1,导入依赖

   <dependency>
         <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
 </dependency>

2,启动类上添加注解: @EnableHystrixDashboard

3,配置ServeletConfig:这里:这里/hystrix.stream路径时固定了,只能时这个路径,不能改变,否则看不到可视化图形界面

/**
 * @Author xiaozq
 * @Date 2022/11/30 10:04
 * <p>@Description:图形化界面</p>
 */
@Configuration
public class HystrixConfig{

    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

访问:http://host:port/hystrix
在这里插入图片描述
点击下面的monitor按钮,则进入下面界面:标识进入监控范围了
在这里插入图片描述
下面来试着对配置了hystrix的方法进行测试,注意,这里没有配置隔离策略,则默认的时线程池隔离策略
在这里插入图片描述
注意上面监控,上图配置中可以看出,10s以内(这是默认的,无法修改),来5个请求,请求失败率达到20%(也就是连续5个请求是失败1个,断路器就会开启),则开启断路器10s,10s后进入半开启状态,此时来一个请求,成功,则断路器关闭,业务正常访问,否则,继续开启断路器10s
.
接下来进行测试:
访问http://localhost:8081/prac2/2,掏出postman发请求访问来连续5次,访问正常,则monitor监控上显示如图所示:
在这里插入图片描述

在这里插入图片描述
.

接下来http://localhost:8081/prac2/1, 访问请求异常的情况,则monitor监控上显示如图所示:
在这里插入图片描述

.

五、网关:Getway ⭐⭐⭐

GetWay作为统一配置的网关,可以实现负载均衡,动态路由以及限流
GetWay作为SpringCloud家族中新一代网关,在性能上比Zuul高上1.5倍
Getway内部实现了负载均衡,不需要手动配置,这点了解一下即可,此在,GetWay天然适配Eureka,能够在夫妻集群中负载均衡,默认采用轮询的方式进行。
GetWay的动态路由也是很大一特点,在下面的学习中会清楚的应用起来 GetWay限流内部默认采用的时redis lua脚本+令牌桶算法进行限流,限流方式很多,例如:ip限流,路径限流等,此在限流默认系统时无法捕捉到异常原因,只会返回code码429

5.1 动态路由

1,导入依赖:

    <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

        <!--基于Redis实现限流-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
            <version>2.0.5.RELEASE</version>
        </dependency>

2,添加注解,将getway服务注册到注册中心上,getway服务端口为8083
在这里插入图片描述
3,配置application,yml文件

静态路由和动态路由的区别在于配置中关于uri的配置,lb://服务名 (标识动态路由,默认采用的负载均衡),如果是写死的ip:port则是静态路路由

需要了解配置文件中三个关键属性

id: 这个代表路由一个服务的标识,一般与服务名一致
uri: 路由地址
predicates: 断言,需要匹配到这个路径,才会路由到uri
filters:限流策略(默认采用令牌桶的限流策略,所以基本配置都是配置令牌桶相关的参数)
eureka:
  client:
    service-url:
      defaultZone: http://eureka8761.com:8761/eureka/ , http://eureka8762.com:8762/eureka/ # 注册的Eureka服务地址
    registry-fetch-interval-seconds: 30
  instance:
    appname: getway-serve

spring:
  application:
    name: getway-serve

  redis:
    host: 120.76.159.196
    port: 6379
    database: 2

  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
        - id: serve1
          uri: lb://SERVE1
          predicates:
            - Path=/ser1/**
          filters:
            - name: SelfRateLimiter # 自定义限流过滤器
              args:
              # 每秒允许处理的请求数量  #  令牌桶每秒填充平均速率
                redis-rate-limiter.replenishRate: 1
              # 每秒最大处理的请求数量# 令牌桶总容量
                redis-rate-limiter.burstCapacity: 1
              # 每次请求获取的令牌数
                redis-rate-limiter.requestedTokens: 1
              #限流策略,对应策略的Bean
                key-resolver: "#{@pathKeyResolver}"

        - id: serve2
          uri: lb://SERVE2
          predicates:
            - Path=/ser2/**
          filters:
#            - name: RequestRateLimiter  # 官方自带
             - name: SelfRateLimiter
               args:
                # 每秒允许处理的请求数量  #  令牌桶每秒填充平均速率
                redis-rate-limiter.replenishRate: 1
                # 每秒最大处理的请求数量# 令牌桶总容量
                redis-rate-limiter.burstCapacity: 1
                # 每次请求获取的令牌数
                redis-rate-limiter.requestedTokens: 1
                #限流策略,对应策略的Bean
                key-resolver: "#{@ipKeyResolver}"

这样通过路由8083端口去访问服务,则效果如图所示:
网关访问服务2,服务2调用服务1 的test1方法,成功!!!
在这里插入图片描述

5.2 限流

在配置yml文件中filter属性配置就是配置限流的策略,限流默认采用令牌桶限流策略
注意,还需要了解一个类: KeyResolver :指定具体的限流对象,例如ip限流,url限流等

在项目代码中,配置了两中限流方式:IP、URL
在这里插入图片描述
注意,在下面配置文件中,filter属性默认的限流name = RequestRateLimiter 这个类,下面配置我采用自定义限流继承RequestRateLimiterGatewayFilterFactory这个类

  routes:
        - id: serve1
          uri: lb://SERVE1
          predicates:
            - Path=/ser1/**
          filters:
            - name: SelfRateLimiter # 自定义限流过滤器
              args:
              # 每秒允许处理的请求数量  #  令牌桶每秒填充平均速率
                redis-rate-limiter.replenishRate: 1
              # 每秒最大处理的请求数量# 令牌桶总容量
                redis-rate-limiter.burstCapacity: 1
              # 每次请求获取的令牌数
                redis-rate-limiter.requestedTokens: 1
              #限流策略,对应策略的Bean
                key-resolver: "#{@pathKeyResolver}"

        - id: serve2
          uri: lb://SERVE2
          predicates:
            - Path=/ser2/**
          filters:
#            - name: RequestRateLimiter  # 官方自带
             - name: SelfRateLimiter
               args:
                # 每秒允许处理的请求数量  #  令牌桶每秒填充平均速率
                redis-rate-limiter.replenishRate: 1
                # 每秒最大处理的请求数量# 令牌桶总容量
                redis-rate-limiter.burstCapacity: 1
                # 每次请求获取的令牌数
                redis-rate-limiter.requestedTokens: 1
                #限流策略,对应策略的Bean
                key-resolver: "#{@ipKeyResolver}"

继承RequestRateLimiterGatewayFilterFactory,限流策略没变,基本是源码复制过来,稍微重写一下,重写的目的是末尾能够将异常原因设置响应给前端

/**
 * 自定义geway限流策略
 */
@Component
public class SelfRateLimiterGatewayFilterFactory extends RequestRateLimiterGatewayFilterFactory {

    private final RateLimiter defaultRateLimiter;

    private final KeyResolver defaultKeyResolver;

    public SelfRateLimiterGatewayFilterFactory(RateLimiter defaultRateLimiter, KeyResolver defaultKeyResolver) {
        super(defaultRateLimiter, defaultKeyResolver);
        this.defaultRateLimiter = defaultRateLimiter;
        this.defaultKeyResolver = defaultKeyResolver;
    }

    @Override
    public GatewayFilter apply(Config config) {

        KeyResolver resolver = getOrDefault(config.getKeyResolver(), defaultKeyResolver);

        RateLimiter<Object> limiter = getOrDefault(config.getRateLimiter(), defaultRateLimiter);

        return (exchange, chain) -> {

            // exchange : DefaultServerWebExchange
            // 示例:对路径,ip限流,
            // resolve: value:"/ser1/test1"、"0:0:0:0:0:0:0:1"
            // 这里获取到路径
            // mono类型都是要采用反应式调用的方式,就好比steam流了,接下载就是对应的api调用,所以这里用到了flatmap
            Mono<String> resolve = resolver.resolve(exchange);
            return resolve.flatMap(key -> {
                        // 获取路由id(服务名)
                        String routeId = config.getRouteId();

                        if (routeId == null) {
                            // yml文件中没配置,则从当前请求上下文exchange中获取key为gatewayRoute的路由信息
                            Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
                            // 获取具体的服务名
                            routeId = route.getId();
                        }

                        String finalRouteId = routeId;

                 // key = "ser1/test"
                // 限流核心方法isAllowed-->redis+lua实现令牌桶算法
                // 返回结果:1,是否允许、 2,剩余令牌有无,没有则-1、 3,流速、生产数、剩余数的map集合
                /** 打印示例如下:
                    transfer-encoding--------[chunked]:分块传输编码
                    X-RateLimit-Remaining--------[0] :剩余量
                    X-RateLimit-Burst-Capacity--------[1]:桶容量
                    X-RateLimit-Replenish-Rate--------[1]:生产令牌速度
                 */
                Mono<RateLimiter.Response> allowed = limiter.isAllowed(routeId, key);
                return allowed.flatMap(response -> {

                    response.getHeaders().entrySet();

                           // response中设置响应信息,响应出去
                            for (Map.Entry<String, String> header : response.getHeaders().entrySet()) {
                                exchange.getResponse().getHeaders().add(header.getKey(), header.getValue());
                            }

                            // 放行
                            if (response.isAllowed()) {
                                return chain.filter(exchange);
                            }

                            // 不放行
                            System.out.println("已限流: " + finalRouteId);

                            ServerHttpResponse httpResponse = exchange.getResponse();

                            //修改code为500
                            httpResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);

                            if (!httpResponse.getHeaders().containsKey("Content-Type")) {
                                httpResponse.getHeaders().add("Content-Type", "application/json");
                            }

                            //此处无法触发全局异常处理,(默认返回429,无其它信息),手动返回response,设置code对应mes信息
                            HashMap<Object, Object> resultMap = new HashMap<>();
                            resultMap.put("code", "429");
                            resultMap.put("mes", finalRouteId + "服务访问人数过多,已限流");
                            resultMap.put("data", "Server throttling");
                            resultMap.put("success", "false");

                            //将map格式转为json
                            String resultJson = JSONObject.toJSONString(resultMap);

                            DataBuffer buffer = httpResponse.bufferFactory().wrap(resultJson.getBytes(StandardCharsets.UTF_8));
                            return httpResponse.writeWith(Mono.just(buffer));
                        });

                    });
        };
    }

    private <T> T getOrDefault(T configValue, T defaultValue) {
        return (configValue != null) ? configValue : defaultValue;
    }
}

此在,在微服务的入口这里,还可以实现令牌的校验,检查登录,做授权服务
本质配置去全局过滤器(后续会采用其他的方式,比如springsecurity+jwt+oauth2做认证授权服务器校验token等),这里大致知道有这么一个过滤器GlobalFilter,Ordered

@Component
public class LoginFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();

        String accessToken = request.getHeaders().getFirst("token");

        if("xzq".equals(accessToken)){
            return chain.filter(exchange);
        }else{
            // 给响应,跳到登录页面
            return login(exchange);
        }
    }

    private Mono<Void> login(ServerWebExchange exchange) {

        HashMap<Object, Object> resultMap = new HashMap<>();
        resultMap.put("code",401);
        resultMap.put("mes","请重新登录授权");
        resultMap.put("status", "401");

        ServerHttpResponse response = exchange.getResponse();
        byte[] bytes = resultMap.toString().getBytes(StandardCharsets.UTF_8);
        response.getHeaders().add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
        // 封装响应数据
        DataBuffer buffer = response.bufferFactory().wrap(bytes);
        return  response.writeWith(Flux.just(buffer));
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

接下啦,用postman测试一下限流效果:
在这里插入图片描述
.

六、链路追踪:Flueth、Zipkin(docker配置组件) ⭐⭐

简单来说: 可以采用Sleuth收集所有服务的日志信息,Sleuth会将收集到的日志发送到Zipkin图形化界面中,更快速的定位到为题发生的服务中
在各个服务中配置,统一发送到图形化界面上

1,导入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
 
// 直接导入下面,因为zipkin依赖包含了slueth依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

2,指定日志级别: 将前端控制器的日志级别设置为DEBUG(因为所有请求都是从前端控制器开始进入的)

logging:
  level: 
    org.springframework.web.servlet.DispatcherServlet: DEBUG

3,配置application.yml文件

zipkin:
    sender:
      type: web
    base-url: http://120.76.159.196:9411
  sleuth:
    sampler:
      probability: 1

这里再serve1和serve2以及网关中加入配置和日志,接下来,启动服务,看控制台!!!!
在这里插入图片描述
注意,这里可以看到,出现了DEBUG [serve2,2393be0d0bcda80b,79db3bf31e734485,true]:解释当前服务,总链路id,子链路id,日志是否发送到其他服务
.

4, 配置slueth搭配zipkin可视化:注意看,可视化的方式,可以直接通过web请求收集,也可以通过irabbitmq收集,也可以通过kafka收集,再实际开发过程中,基本都是通过队列实现,因为通过web请求是同步处理的方式,耗时,这样采用异步的方式将日志发送到队列上在可视化到zipkin上,性能好很多!!!
.

关于收集和是持久化日志:

1,收集日志方式Rabiit、Kafka的方式的话,需要配置rabbit,例如采用docker配置,然后配置文件加入配置即可,这里就简单采用web当时看效果啦
.
2,Sleuth异步传输数据到Zipkin,避免Sleuth以Web的方式发送日志信息给Zipkin会造成额外的性能损耗可以通过RabbitMQ实现异步的方式,让Sleuth将日志发送到消息队列,让Zipkin收集即可
.
3, Zipkin默认采用内存存储数据,导致Zipkin重启后,数据全部丢失。
Zipkin也提供了响应的持久化方案,比较熟悉的是ES和MySQL,其中ES更适合存储海量数据,采用ES作为持久化方案只需要Zipkin设置好ES的地址信息,Zipkin会自动创建索引,存储日志信息

方式一:web
在这里插入图片描述

5,接下来就是演示效果截图
访问链接:http://120.76.159.196:9411/zipkin/
在这里插入图片描述

接下来从getway网关服务开始,网关路由serve2,serve2远程调用serve1的方法,postman测一下看效果
postman测一下,出现一条日志
在这里插入图片描述
在这里插入图片描述
在下图中可以清晰的看到服务之间的调用,以及调用的那个方法吗,时间长久相对长久,根据时间判断在调用过程中,那个服务请求的时间长,然后可以做具体的优化!!!!,真的一目了然
在这里插入图片描述

在下面两张图中,都可以很清晰的看到请求调用浏览器开始时间,结束时间,经过服务器开始结束时间,以及指定看一个服务器可以看到请求经过的的服务的方法、具体的请求方式Get、路径,controller类,方法名等,真的详细,另外在途中最后中可以看到服务serve1调用出问题,红色代表出现异常

http.method
GET
http.path
/ser2/test1
mvc.controller.class
Serve2Controller
mvc.controller.method
getServe1Info1

在这里插入图片描述
在这里插入图片描述
.
.

最后,赋springcloud简单总结资料:getway换成zuul也简单了解一下吧
在这里插入图片描述在这里插入图片描述

.
至此,微服务的基本组件的了解和应用就到此结束了…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/83099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MongoDB和MongoTemplate对于嵌套数据的判空查询

前言&#xff1a; 不知道有没有和小名一样&#xff0c;接触MongDB时间不长的小伙伴。由于MongoDB是以文档形式存储数据的&#xff0c;所以其中的数据类型相对MySql或者Oracle关系型数据库丰富一些&#xff08;MongoDB是NoSQL数据库这里比较不是很准确&#xff09; 我们在关系…

Dropout方法原理和使用方法

来源&#xff1a;投稿 作者&#xff1a;梦飞翔 编辑&#xff1a;学姐 为什么提出这种方法&#xff1f; 神经网络在训练过程中&#xff0c;由于正负样本不均衡、样本特征显著性不足、训练参数不合适等原因会导致发生过拟合现象&#xff0c;即模型参数陷入局部最优&#xff0c;仅…

QT6操作连接mysql数据库方法_增删改查

QT6操作mysql方法_增删改查 mysql数据库搭建相关方法&#xff1a; MySQL - 随笔分类 - txwtech - 博客园https://www.cnblogs.com/txwtech/category/1973054.htmlMySQL解压版配置方法 MySQL解压版配置方法 - txwtech - 博客园1.下载 https://downloads.mysql.com/archives/co…

【知识学习】C++QT配置opencv遇到的坑

最近要搞图像&#xff0c;老师说尽量用C&#xff0c;就开始研究配置opencv 当然&#xff0c;说在前面&#xff0c;C的比python的要麻烦特别多&#xff0c;所以如果不是必要的话&#xff0c;建议用python pip配opencv吧 C麻烦就在于要自己在本地编译一遍才能跑&#xff0c;直接…

如何将亚马逊Seller Central 用到极致~

不论是新手卖家还是有经验的老手&#xff0c;亚马逊卖家中心都是一个可以帮助卖家发展业务的好工具&#xff0c;对于许多新手小白来说&#xff0c;亚马逊这样巨大的平台仍有许多功能与服务等着挖掘。 什么是亚马逊卖家中心&#xff1f; 亚马逊卖家中心是第三方卖家用来管理和…

微信支付-全面详解(学习总结---从入门到深化)

微信支付_产品介绍 微信支付介绍 微信支付&#xff08;https://pay.weixin.qq.com&#xff09;是腾讯集团旗下中国领先 的第三方支付平台&#xff0c;一直致力于为用户和企业提供安全、便捷、专业的在线支付服务。 付款码支付 付款码支付是指用户展示微信钱包内的“付款码”给商…

指纹浏览器是什么?可以用来解决网络爬虫的什么问题?

在大数据时代的今天&#xff0c;各行各业的许多企业多多少少都会因为涉及到海外市场需要收集大量的市场信息&#xff0c;特别是对于跨境电商领域的商家来说&#xff0c;网络爬虫是必不可少的。因此&#xff0c;一定有很多从业者接触过网络爬虫&#xff0c;但对于刚打算进入这个…

ADI Blackfin DSP处理器-BF533的开发详解36:图像处理专题-RGB888 转 RGB565(含源代码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 功能介绍 作为一个最高600M主频&#xff0c;单核或双核的定点DSP&#xff0c;做图像处理还是挺行的&#xff0c;属于是老本行&#xff0c;那么我…

广州蓝景分享—HTML+CSS功能,让页面加载速度提高数倍

Hello&#xff0c;各位小伙伴&#xff0c;今天跟大家分享前端技术干货&#xff0c;页面加载速度问题。 首先我们都讨厌加载缓慢的页面&#xff01; 要知道加载时间每增加1秒&#xff08;0-5秒之间&#xff09;&#xff0c;网站转化率就会平均下降4.42%。页面加载时间的前五秒…

linux 虚拟机nat模式网络配置

文章目录1. linux 版本&#xff1a;2. 下载地址 Index of /centos-store/7.6.1810/isos/x86_64/ (liu.se)3. 账号密码&#xff1a;root root4.选择nat 模式&#xff0c;勾选 将主机虚拟适配器连接到此网络&#xff0c;勾选 使用本地DHCP服务将iP地址分配给虚拟机5.点击Nat 设置…

数据仓库分享

前言 数据仓库&#xff0c;是为企业所有级别的决策制定过程&#xff0c;提供所有类型数据支持的战略集合。它出于分析性报告和决策支持的目的而创建的。 数据仓库是一个数据集合 数据仓库是一个为业务决策提供数据支持的数据集合 数据仓库是通过监控业务流程的形式为业务决策提…

Css不常用的方法

flex布局换行之后&#xff0c;下面一行的布局会异常 .homeItemBox{ display: flex; flex-wrap: wrap; justify-content: flex-start;} .homeItem{ display: flex; width: calc((100% - 20rpx) / 4); flex-direction: column; align-items: center; flex-shrink: 0; …

盘点系列:一度大热的TWS耳机今年表现如何?

根据Canalys最新市场研究数据显示&#xff0c;全球智能个人耳机市场在2022年Q3已连续第二个季度出现下滑&#xff0c;出货量同比下降4%至1.136亿台。 而TWS是唯一出现增长的子类别&#xff01; Q3真无线耳机TWS销量达7690万部&#xff0c;同比增长6%。苹果&#xff08;含beats&…

软件测试基础理论体系学习6-黑盒测试方法白盒测试方法简述

13 白盒测试方法1 黑盒测试1.1 黑盒测试概述1.2 黑盒测试的使用场景1.3 “黑盒”的两种基本方法1.4 黑盒测试的优缺点1.4.1 优点1.4.2 缺点1.5 黑盒测试的测试用例设计方法2 白盒测试2.1 白盒测试概述2.2 逻辑覆盖2.3 语句覆盖2.3.1 基本思想是2.3.2 优点2.3.3 缺点2.4 判定覆盖…

Python及其在数据科学中的应用

前言 Python及其在数据科学中的应用 Python易学&#xff0c;语法也比较简单。它是一种流行的数据科学语言&#xff0c;因为它功能强大且易于使用。Python是一种出色的数据分析语言&#xff0c;因为它包含各种数据结构、模块和工具。 使用Python进行数据科学的原因有很多&…

详细介绍NLP对话系统

任务型对话系统 任务型对话系统主要应用于固定领域。任务型对话的广泛应用的方法有两种&#xff0c;一种是模块法&#xff0c;另一种是端到端的方法。 模块法是将对话响应视为模块&#xff0c;每个模块负责特定的任务&#xff0c;并将处理结果传送给下一个模块。 端到端的任务…

分布式事务 - Seata - TCC模式

目录一、什么是TCC二、AT & TCC区别 及 适用场景三、代码集成示例3.1 升级Seata 1.5.23.2 示例场景说明3.3 TCC核心接口定义3.4 TCC相关阶段规划3.5 TCC核心代码四、TCC三大问题&#xff08;幂等、空回滚、悬挂&#xff09;之前介绍过分布式事务之Seata AT模式&#xff0c;…

智慧新零售异业联盟帮你搞定多店跨界整合,让你开启共富时代

大家好&#xff0c;我是林工&#xff0c;在如今的时代&#xff0c;不管你所看到的商业模式是什么样的&#xff0c;以不变应万变&#xff0c;目的只有一个&#xff0c;把买卖发展壮大&#xff0c;想要将买卖发展壮大&#xff0c;那就需要精准的吸粉引流获客方式和能力。 林工常常…

Fluent Mybatis 牛逼!

这玩意比ThreadLocal叼多了&#xff0c;吓得我赶紧分享出来。 推荐一些chrome浏览器必装的插件&#xff01; 40 个 SpringBoot 常用注解 VSCode 花式玩法&#xff08;摸鱼&#xff09;收藏一下 &#xff01; 使用fluent mybatis可以不用写具体的xml文件&#xff0c;通过jav…

【面试大全】互联网面试软实力【必看】

软实力 推荐大家使用Markdown语法写简历&#xff0c;然后再将Markdown格式转换为PDF格式后进行简历投递。如果你对Markdown语法不太了解的话&#xff0c;可以花半个小时简单看一下Markdown语法说明: http://www.markdown.cn/ 面试 假如你是网络申请者【拉勾、boss等】&…