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);
}
相关推荐
星哥说事7 分钟前
灾难恢复(DR):RTO/RPO 定义、冷备/热备/双活架构
架构
uuukashiro16 分钟前
数据湖可以进行Upsert吗?腾讯云DLC用Serverless架构破解实时数据更新难题
ai·架构·serverless·腾讯云
roman_日积跬步-终至千里1 小时前
【Docker下部署高可用】StarRocks 存算一体架构高可用部署要点
docker·容器·架构
uuukashiro2 小时前
多模态数据管理挑战重重?腾讯云数据湖计算DLC以Serverless架构破局
ai·架构·serverless·腾讯云
Lei活在当下10 小时前
【现代 Android APP 架构】09. 聊一聊依赖注入在 Android 开发中的应用
java·架构·android jetpack
pan30350747910 小时前
GRPC详解
微服务·grpc
一尘之中11 小时前
【架构人生】一种“低耦合、高内聚”的处世哲学
架构·ai写作
喵个咪11 小时前
开箱即用的GO后台管理系统 Kratos Admin - 站内信
后端·微服务·go
Ryan今天学习了吗17 小时前
💥不说废话,带你上手使用 qiankun 微前端并深入理解原理!
前端·javascript·架构
陈果然DeepVersion17 小时前
Java大厂面试真题:Spring Boot+微服务+AI智能客服三轮技术拷问实录(四)
spring boot·redis·微服务·kafka·spring security·智能客服·java面试