Sentinel微服务保护

基础

特点:懒加载

运行命令

java -jar sentinel-dashboard-1.8.1.jar  

指定端口号运行

java -Dserver.port=9090 -jar sentinel-dashboard-1.8.1.jar

使用步骤

  1. 导入依赖
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.9.RELEASE</version>
  </parent>
  <groupId>com.ape</groupId>
  <artifactId>springboot_sentinel</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>
  <properties>
    <java.version>8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!-- 统一管理版本 -->
    <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
    <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
  </properties>
  <modules>
    <module>shop_common</module>
    <module>shop_product</module>
    <module>shop_order</module>
  </modules>
  <!-- 使用dependencyManagement管理 并且指定依赖版本 子项目就可以不用写版本了 -->
  <dependencyManagement> 
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>${spring-cloud-alibaba.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>
  1. 子项目中导入依赖
XML 复制代码
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  1. 配置文件

    spring:
    cloud:
    sentinel:
    transport:
    dashboard: localhost:9090

访问localhost:9090 输入用户与密码进入图形化界面 因为是懒加载所以没有信息

访问接口 localhost:8090/order/1 可以看到图形化界面中有了信息

流量控制

直接流量控制模式
  1. 添加流量控制
  1. 设置详情信息
  • QPS即每秒查询率,QPS = req/sec = 请求数/秒,即每秒的响应请求数,也即是最⼤吞吐能⼒
关联流控模式

解释: 统计与当前资源相关的另⼀个资源,触发阈值时,对当前资源限流 假设A规则关联B,当B超过单机阈值那么A资源是受限制的

情景说明: ⽐如⽤户⽀付时需要修改订单状态,同时⽤户要查询订单。查询和修改操作会争抢数据库锁,产⽣竞争。业务需求是优先⽀付和更新订单因此当修改订单业务触发阈值时,需要对查询订单业务限流。

1000个⽤户,100秒,因此QPS为10,超过了我们设定的阈值:5 请求的⽬标是/order/update,超过阈值后会对/order/query进行限流 /order/update不限流

链路流控模式

解释: 阈值统计时,只统计从指定资源进⼊当前资源的请求,是对请求来源的限流

举例: 有查询订单和更新订单业务,两者都需要查询商品。针对从查询订单进⼊到查询商品的请求统计,并设置限流。

步骤:

  1. 在OrderService中添加⼀个queryGoods⽅法,不⽤实现业务 使用@SentinelResource("goods")注解使业务层暴露出来
java 复制代码
@Override
@SentinelResource("goods")
public void queryGoods(){
    System.out.println("查询商品");
}
  1. 在OrderController中,改造/order/query端点,调⽤OrderService中的queryGoods⽅法
java 复制代码
@GetMapping("/query")
public String query(){
    service.queryGoods();
    return "查询订单";
}
  1. 在OrderController中添加⼀个/order/save的端点,调⽤OrderService的queryGoods⽅法
java 复制代码
@PutMapping("/updateOrder")
public String update(){
    service.queryGoods();
    return "修改订单";
}
  1. 给queryGoods设置限流规则,从/order/query进⼊queryGoods的⽅法限制QPS必须⼩于2

链路模式中,是对不同来源的两个链路做监控。但是sentinel默认会给进⼊SpringMVC的所有请求设置同 ⼀个root资源,会导致链路模式失效。 我们需要关闭这种对SpringMVC的资源聚合,修改order-service服务的application.yml⽂件:

spring:
  cloud:
    sentinel:
      web-context-unify: false # 关闭Context整合

流控效果

快速失败

达到阈值后,新的请求会被⽴即拒绝并抛出FlowException异常。是默认的处理⽅式。

warm up

预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从⼀个较⼩值逐渐增加到最⼤阈值。

冷启动的 默认阈值= 最大阈值/3

对/order/query 最大限流为一秒10个请求 那么冷启动的阈值为 10/3 = 3 在5秒后达到最大阈值10

这个配置的意思就是在5秒后 达到最大阈值10

排队等待

当请求超过QPS阈值时,快速失败和 warm up 会拒绝新的请求并抛出异常。

排队等待则是让所有请求进⼊⼀个队列中,然后按照阈值允许的时间间隔依次执⾏。后来的请求必须等待前⾯执⾏完成,如果请求预期的等待时间超出最⼤时⻓,则会被拒绝。

⼯作原理 例如:QPS = 5,1s处理5个请求,意味着每200ms处理⼀个请求;timeout = 2s,意味着预期等待时⻓超过 2s的请求会被拒绝并抛出异常。

那什么叫做预期等待时⻓呢? ⽐如现在⼀下⼦来了12 个请求,因为每200ms执⾏⼀个请求,那么:

第6个请求的预期等待时⻓ = 200 * (6 - 1) = 1000ms

第12个请求的预期等待时⻓ = 200 * (12-1) = 2200ms 超过2s就会失败

举例:

最大阈值为10 1s处理10个请求 每个请求要100ms 等待时间为5s 超过5s的等待请求会被拒绝

如果有300个请求在20s内完成 那么QPS就是15 超出了最大阈值

最后一个请求等待时间 = 100ms * (15-1) = 1400ms 在设置的超时时间之内,所以所有请求都能成功

此时将测试用例重新设置 QPS为30 那么最后一个的等待时间是 100ms * (30 - 1) = 2900ms还是可以成功

热点参数限流

刚才的配置中,对查询商品这个接⼝的所有商品⼀视同仁,QPS都限定为5. ⽽在实际开发中,可能部分商品是热点商品,例如秒杀商品,我们希望这部分商品的QPS限制与其它商 品不⼀样,⾼⼀些。那就需要配置热点参数限流的⾼级选项了

需求: 给/order/prod/{pid}这个资源添加热点参数限流,规则如下:

  • 默认的热点参数规则是每1秒请求量不超过2
  • 给1这个参数设置例外:每1秒请求量不超过10

使用流程:

  1. controller层的方法添加注解

    @SentinelResource("hot") //热点限流 必须要用这个注解
    @GetMapping("/{id}")
    public Order selectById(@PathVariable int id) {
    return service.getById(id);
    }

  2. 添加规则

除了访问/order/1 阈值是5 访问其他的都是2

隔离和降级

限流是⼀种预防措施,虽然限流可以尽量避免因⾼并发⽽引起的服务故障,但服务还会因为其它原因⽽ 故障。 ⽽要将这些故障控制在⼀定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级⼿段了。

线程隔离之前讲到过:调⽤者在调⽤服务提供者时,给每个调⽤的请求分配独⽴线程池,出现故障时, 最多消耗这个线程池内资源,避免把调⽤者的所有资源耗尽。

熔断降级:是在调⽤⽅这边加⼊断路器,统计对服务提供者的调⽤,如果调⽤的失败⽐例过⾼,则熔断 该业务,不允许访问该服务的提供者了。 可以看到,不管是线程隔离还是熔断降级,都是对客户端(调⽤⽅)的保护。需要在调⽤⽅ 发起远程调 ⽤时做线程隔离、或者服务熔断。

⽽我们的微服务远程调⽤都是基于Feign来完成的,因此我们需要将Feign与Sentinel整合,在Feign⾥⾯ 实现线程隔离和服务熔断

FeignClient整合Sentinel

注意:配置文件中springcloud版本是Hoxton.SR8 如果是10 会有循环依赖的错误

  1. 配置文件添加以下内容

    feign:
    sentinel:
    enabled: true # 开启feign对sentinel的⽀持

  2. 编写失败降级逻辑

java 复制代码
package com.ape.shop_order.service.impl;

import com.ape.pojo.Product;
import com.ape.shop_order.service.ProductService;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

//降级方案
@Component
public class ProductServiceFallBack implements FallbackFactory<ProductService> {
    @Override
    public ProductService create(Throwable throwable) {
        return new ProductService() {
            @Override
            public Product selectById(int id) {
                Product product = new Product();
                product.setPid(-1);
                product.setPName("暂无商品");
                return product;
            }
        };
    }
}
  1. 发通信的接口

@FeignClient(value = "server-product",fallbackFactory = ProductServiceFallBack.class)

java 复制代码
package com.ape.shop_order.service;

import com.ape.pojo.Product;
import com.ape.shop_order.service.impl.ProductServiceFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "server-product",fallbackFactory = ProductServiceFallBack.class)
public interface ProductService {
    @GetMapping("/product/{id}")
    Product selectById(@PathVariable int id);
}
相关推荐
FIN技术铺2 小时前
Redis集群模式之Redis Sentinel vs. Redis Cluster
数据库·redis·sentinel
mit6.8246 小时前
[Docker#4] 镜像仓库 | 部分常用命令
linux·运维·docker·容器·架构
林戈的IT生涯6 小时前
一个基于Zookeeper+Dubbo3+SpringBoot3的完整微服务调用程序示例代码
微服务·rpc·dubbo
乌恩大侠11 小时前
了解 Open RAN 架构中的 DU 和 CU
架构
贵州晓智信息科技11 小时前
深入理解 React 架构从概览到核心机制
前端·react.js·架构
W Y11 小时前
【架构论文-1】面向服务架构(SOA)
架构·架构设计
Hello.Reader11 小时前
解析Eureka的架构
云原生·eureka·架构
航火火13 小时前
回首遥望-C++内存对齐的思考
c++·面试·架构
执着码农14 小时前
Tomcat源码解析之架构设计
后端·架构
白总Server16 小时前
Swagger UI
后端·ui·spring cloud·ribbon·架构·scala·1024程序员节