首页 > 其他分享 >决战圣地玛丽乔亚Day02

决战圣地玛丽乔亚Day02

时间:2023-01-29 23:57:29浏览次数:61  
标签:令牌 乔亚 请求 阈值 Day02 玛丽 断路器 payment 路由

OpenFeign:

负载均衡+RPC调用

启动类添加@EnableFeignClients,

业务逻辑接口添加 @FeignClient(name = "定义当前客户端client名字")  如果client同名,可以用contextId起别名。 

然后实现类继承逻辑接口,写具体实现,Controller调用的时候,直接调用加了OpenFeign的接口即可

 

OpenFeign超时控制:

如果生产者需要处理3s,消费者请求1s,就会出现超时的情况。OpenFeign客户端(消费者)的等待时间默认是1s

OpenFeign的底层使用Ribbon,所以设置超时时间也是改Ribbon的配置:

ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000

表示的是我OpenFeign客户端可以等待5秒中,而现在支付微服务提供者的处理时间需要3秒钟,再来测试是没有问题的。

 

OpenFeign的日志打印功能:

日志:对Feign接口的调用情况进行监控并输出

日志级别:

  • NONE:默认的,不显示任何日志;

  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;

  • HEADERS:除了BASIC中定义的信息外,还有请求和响应的头信息;

  • FULL:除了HEADERS中定义的信息外,还有请求和响应的正文及元数据。

首先配置日志的Bean:

@Configuration
public class FeignLogConfig {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}

然后配置Yml文件需要开启日志的Feign客户端:

Feign客户端是加了@FeignClient的那个接口的路径

logging:
level:
cn.bdqn.service.PaymentFeignService: debug

 

Hystrix断路器:

服务的扇出链路多,如果每个环节出问题就会长时间占用资源导致系统崩溃。

缓存雪崩问题。

问题:

如果用高并发压测去测生产者微服务,出现了转圈卡顿,线程被打满没有多余线程分解压力。

如果生产者被打满,消费者再去调用生产者,就会转圈或者超时。

解决方式:

如果转圈/超时--->不再等待

出错(宕机/运行出错)--->有一个默认的处理方式去执行。降级!

 

降级:

生产者自身修复

@HystrixCommand

设置一个自身调用的时间限制,超过多少时间视为异常进行降级处理。

@HystrixCommand(fallbackMethod = "getInfo_timeoutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})

在这里,自己写一个fallbackmethod处理降级

启动类加注解:@EnableCircuitBreaker

 

消费者自身修复:

1.添加Yml配置

feign:
  hystrix:
    enabled: true

2.在启动类添加@EnableHystrix注解

3.在对应接口添加

@HystrixCommand(fallbackMethod = "getInfo_timeoutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})

 问题一、冗余

如果每个接口我们都写一个降级方法,会造成代码的臃肿,我们可以写一个公共的降级方法,对于那些没有指定降级方法的接口统一调用默认的降级方法。

@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")

 问题二、解耦

把降级方法和业务逻辑代码写在一起耦合度过高

我们可以重新写一个特定业务的降级实现类,让该类继承业务实现类。

并在业务实现类中通过注解指定降级方法。

例如:

单写一个对应的业务降级实现类:PaymentFallbackService

继承业务实现类。  PaymentFallbackService implements PaymentService

在业务实现类中使用注解标明降级方法:

@FeignClient(name = "springcloud-provider-hystrix-payment" ,
fallback = PaymentFallbackService.class)

public interface PaymentService {xxxxxx}

 

熔断break

1.修改HystrixCommand注解

// 在10秒内,如果10(或者以上)次请求有6次是失败的,就会进行服务熔断
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少后跳闸
})

服务降级---->服务熔断----->恢复链路

服务降级是保底方法,熔断是一段时间内的失败次数过多的措施,然后才会通过监听慢慢恢复链路。熔断后,就算是调用正确也不会立刻恢复。

 

涉及到断路器的三个重要参数:快照时间窗/时间范围、请求总数阈值、错误百分比阈值。

  • 1、快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。

  • 2、请求总数阈值:在快照时间窗内,必须满足请求总数阈值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。

  • 3、错误百分比阈值:当请求总数在快照时间窗内超过了阈值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阈值情况下,这时候就会将断路器打开。

断路器开启/关闭的条件:

  • 1、当满足一定的阈值的时候(默认10秒内超过20个请求次数)

  • 2、当失败率达到一定的时候(默认10秒内超过50%的请求失败)

  • 3、到达以上阈值,断路器将会开启

  • 4、当开启的时候,所有请求都不会进行转发

  • 5、一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。重复4和5

 

链路恢复:

1、断熔后,再有请求调用的时候,将不会调用主逻辑,而是直接调用降级fallback,通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。

2、原来的主逻辑要如何恢复呢?对于这一问题,hystrix也为我们实现了自动恢复功能。当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,当休眠时间窗到期,断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。

 

总结:断路器在监听请求的失败率达到一定次数时进行服务降级策略,原来的主逻辑被替换为降级逻辑的实现,然后有一个休眠时间窗(就像冷静期一样),等冷静期一到,断路器会变成半开状态,试探的把一次请求交给主逻辑运行,如果运行无误就恢复链路调用。

 

GateWay网关:

yml文件:

server:

  port: 9500

 

spring:

  application:

    name: springcloud-gateway

  cloud:

    gateway:

      routes:

        - id: payment_routh1 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名

          uri: http://localhost:8001

          predicates:

            - Path=/payment/get/** #断言,路径相匹配的进行路由

 

        - id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名

          uri: http://localhost:8001

          predicates:

            - Path=/payment/getInfo/** #断言,路径相匹配的进行路由

 

eureka:

  client:

    register-with-eureka: true

    fetch-registry: true

    service-url:

      defaultZone: http://eureka7001.com:7001/eureka,

        http://eureka7002.com:7002/eureka,

        http://eureka7003.com:7003/eureka

  instance:

    prefer-ip-address: true # 使用ip地址注册

相当于在请求某个接口路径的时候,在外面再套一层网关,通过网关去进行过滤,路由,监控等操作。

例如我们请求8001接口,但是我们套一层端口为9500的网关,这样请求的时候用9500端口即可,安全性保证。

一般我们不会在网关的配置文件把对应的路由地址写死,使用服务名进行动态路由。如下:

yml:

server:

  port: 9500

 

spring:

  application:

    name: springcloud-gateway

  cloud:

    gateway:

      discovery:

        locator:

          enabled: true # 开启从注册中心动态创建路由的功能,,利用微服务名进行路由

      routes:

        - id: payment_routh1 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名

          #uri: http://localhost:8001

          uri: lb://springcloud-payment-provider-service

          predicates:

            - Path=/payment/get/** #断言,路径相匹配的进行路由

 

        - id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名

          #uri: http://localhost:8001

          uri: lb://springcloud-payment-provider-service

          predicates:

            - Path=/payment/getInfo/** #断言,路径相匹配的进行路由

 

eureka:

  client:

    register-with-eureka: true

    fetch-registry: true

    service-url:

      defaultZone: http://eureka7001.com:7001/eureka,

        http://eureka7002.com:7002/eureka,

        http://eureka7003.com:7003/eureka

  instance:

 

    prefer-ip-address: true # 使用ip地址注册

 

在这里的url的lb标识loadbalance,使用gateway的负载均衡功能

断言有很多种形式,path方式只是其中的一种。

path:路径

before:在某个时间点前

after:在某个时间点后

between:在时间点之间

cookie:cookie值匹配

header:header值匹配

host:根据主机名匹配

Method:根据请求方式

Query:参数

RemoteAddr:指定ip地址

也可以配置多个断言,满足所有断言后才能够进行路由转发。

gateway过滤器

生命周期pre和post

pre:这种过滤器在请求被路由之前调用,我们可以利用这种过滤器实现身份验证,在集群中选择请求的微服务,日志的记录等。

post:这种过滤器在路由到微服务以后执行,这种过滤器可用来为响应添加标准的http header,收集统计信息和指标、将响应从微服务发送给客户端。

局部过滤器(GatewayFilter):是针对单个路由的过滤器,可以对访问的url过滤,进行切面处理

全局过滤器(GlobalFilter):通过全局过滤器可以实现对权限的统一校验,安全性验证等功能,并且全局过滤器也是我们使用最多的过滤器,所以要重点掌握

  自定义全局过滤器:1.实现GlobalFilter , Ordered两个接口。分别实现Filter和getOrder方法,实现过滤器的具体逻辑和执行顺序。

在一般的开发中的权限认证/鉴权:1.客户端首次登陆,服务器对用户进行信息认证,颁发token作为之后的登陆凭证,之后客户端登陆通过token来鉴别是否有权限。

网关过滤算法:

1.计数器算法:

单位时间内请求有一个阈值,如果请求超过阈值,之后的请求都被拒绝,除非单位时间过去。

比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个。那么我们可以这么做:在一开始的时候,我们可以设置一个计数器counter,每当一个请求过来的时候, counter就加1,如果counter的值大于100并且该请求与第一个请求的间隔时间还在1分钟之内,那么说明请求数过多; 如果该请求与第一个请求的间隔时间大于1分钟,且counter的值还在限流范围内,那么就重置 counter。

弊端:对于秒级以上的时间周期来说,会存在一个非常严重的问题,那就是临界问题。 如果时间单位是分钟,那么恶意攻击可以发生在1s内大量请求,压垮服务器

2.漏桶算法:

控制流量的速率,大流量打进来,也只是保留一定的数据,溢出一部分数据。

弊端:针对小数据量和稍大的数据量来说,速率是一定的,所以大流量吃亏。

3.令牌桶算法:

以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。

放令牌这个动作是持续不断的进行,如果桶中令牌数达到上限,就丢弃令牌,所以就存在这种情况,桶中一直有大量的可用令牌,这时进来的请求就可以直接拿到令牌执行。

随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS(每秒查询率)=100,则间隔是10ms)往桶里加入Token,那么限流器初始化完成一秒后,桶中就已经有100个令牌了

令牌桶算法生成令牌的速度是恒定的而请求去拿令牌是没有速度限制的。

这意味,面对瞬时大流量,该算法可以在短时间内请求拿到大量令牌,可以处理瞬时流量,而且拿令牌的过程并不是消耗很大的事情。令牌桶算法通常可以用于限制被访问的流量,保护自身系统。

 

gateway限流:

gateway的限流是通过内置的过滤器工厂 RequestRateLimiterGatewayFilterFactory。 通过Redis和lua脚本结合的方式进行流量控制。

限流的yml配置:

spring: application: name: springcloud-gateway redis: host: localhost port: 6379 database: 0 cloud: gateway: discovery: locator: enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由 routes: - id: payment_routh1 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 uri: lb://springcloud-payment-provider-service predicates: - Path=/payment/get/** #断言,路径相匹配的进行路由 - id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 uri: lb://springcloud-payment-provider-service predicates: - Path=/payment/getInfo/** #断言,路径相匹配的进行路由 filters: - name: RequestRateLimiter   args: key-resolver: '#{@hostAddrKeyResolver}' redis-rate-limiter.replenishRate: 1 redis-rate-limiter.burstCapacity: 3

主要关注三个参数:

  • burstCapacity,令牌桶总容量。

  • replenishRate,令牌桶每秒填充平均速率。

  • key-resolver,用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。

 

编写key-resolver:

@Configuration

public class KeyResolverConfig {

 

    @Bean

    public KeyResolver pathKeyResolver(){

        return new KeyResolver() {

            @Override

            public Mono<String> resolve(ServerWebExchange exchange) {

                return Mono.just(exchange.getRequest().getPath().toString());

            }

        };

    }

}

 

gateway的高可用:

nginx集群-->gateway集群--->微服务集群

涉及到断路器的三个重要参数:快照时间窗/时间范围、请求总数阈值、错误百分比阈值。

  • 1、快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。

  • 2、请求总数阈值:在快照时间窗内,必须满足请求总数阈值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。

  • 3、错误百分比阈值:当请求总数在快照时间窗内超过了阈值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阈值情况下,这时候就会将断路器打开。

标签:令牌,乔亚,请求,阈值,Day02,玛丽,断路器,payment,路由
From: https://www.cnblogs.com/dwj-ngu/p/17072490.html

相关文章

  • 决战圣地玛丽乔亚Day01
    SpringCloud的服务注册与发现:单机的服务注册与发现需要配置一个服务注册中心,一个生产者微服务,一个消费者微服务。注册中心:   服务的生产者:服务的消费者: 配......
  • 数学建模学习——Day02
    一、Matlab基础知识入门1.每行语句后面加上英文分号,表示不显示运行结果,分号也表示换行2.多行注释:选中要注释的语句,CTRL+R3.取消注释:选中要取消注释的语句,CTRL+T4.cle......
  • Day02 - MySQL的条件查询
    1.聚合函数聚合函数的介绍聚合函数又叫组函数,通常是对表中的数据进行统计和计算,一般结合分组(groupby)来使用,用于统计和计算分组数据。常用的聚合函数:1.count(co......
  • Day02 - JavaScripts
    1.javascript介绍JavaScript的定义JavaScript是运行在浏览器端的脚步语言,是由浏览器解释执行的,简称js,它能够让网页和用户有交互功能,增加良好的用户体验效果。......
  • day02 - Linux高级命令
    1.echo和重定向a.echo$?显示上一次命令或程序的执行状态码b.echo$PATH显示系统环境变量PATHa.>输出重定向,用来将输出到屏幕的数据,重定向到一个指定......
  • Day02函数和条件表达
    0.格式化字符串'''格式化字符串'''print(1)print(1,2,3,4)a=1b=2.1123c='hello's='a=%db=%fc=%s'%(a,b,c)s+='--world'print(s)......
  • bbs复习day02
    day027.注册功能1.添加路由2.编写view函数3.单独开设一个py文件编写注册的信息对比4.开设html页面编写注册样式5.发送ajax请求能够注册成功难点:注册信息的校......
  • Day02 变量的使用
    1、变量的作用存储数据变量分为变量名,变量值,内存地址id() 获取内存地址2、变量命名规则1)变量的名字只能由字母、数字、下划线组成2)数字不能作为开头(支持中文变量名称......
  • day02-Spring基本介绍02
    Spring基本介绍025.简单模拟Spring基于XML配置的程序5.1需求说明自己写一个简单的Spring容器,通过读取beans.xml,获取第一个Javabean:Monster的对象,给该对象属性赋值,放入......
  • Go语言学习之 Day02
    数组赋值二维数组切片切片操作slice内存slice切片操作slice元素删除点击查看代码1.所有资料,上课代码,同学作业=>githubweb链接:https://git......