SpringCloud---Sentinel

限流

限流的目的防止恶意请求流量、恶意攻击,或者防止流量超过系统峰值

sentinel使用环境搭建

  1. 添加pom依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

  1. 添加yml文件sentinel配置
spring:
  cloud:
    sentinel: # 位置在cloud元素下, 与nacos是并列关系
      transport:
         dashboard: localhost:8180 # 指定sentinel控制台地址。

  1. 创建一个用于演示限流操作的Controller对象
package com.jt.provider.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/provider")
public class ProviderSentinelController {
       @GetMapping("/sentinel01")
       public String doSentinel01(){
           return "sentinel 01 test  ...";
       }
}

  1. 启动sca-provider服务,然后对指定服务进行访问

image-20211204122130287

  1. 刷新sentinel 控制台,实时监控信息

image-20211204122117630

设置限流,默认直接模式

  1. 选择要限流的链路

    image-20211204122220103

  2. 设置限流策略

image-20211204122234664

  1. 反复刷新访问消费端端服务,检测是否有限流信息输出

image-20211204122244962

关联模式

当关联的资源达到阈值,就限流自己

比如: 一个是读取订单信息接口,一个是写入订单信息接口, 可利用关联模式, 一旦写入请求多,就限制读的请求

  1. 添加方法二
   @GetMapping("/sentinel02")
   public String doSentinel02(){
     return "sentinel 02 test  ...";
   }

  1. 在sentinel中设置关联模式限流设计

image-20211204122257559

  1. 打开两个测试窗口,对/provider/sentinel02进行访问,检查/provider/sentinel01的状态

image-20211204122306733

链路模式

只记录指定链路入口的流量
  1. 创建一个ResourceService类

image-20211204122316291

package com.jt.provider.service;
@Service
public class ResourceService{

    @SentinelResource("doGetResource")
    public String doGetResource(){
        return "doGetResource";
    }
}

  1. 在Controller里添加方法三, 并获取service实例
    @Autowired
    private ResourceService resourceService;
    @GetMapping("/sentinel03")
    public String doSentinel03() throws InterruptedException {
        resourceService.doGetResource();
        return "sentinel 03 test";
    }

  1. 在sentinel中配置链路模式限流规则

image-20211204122328526

image-20211204122338385

  1. 设置链路流控规则后,再频繁对限流链路进行访问,检测是否会出现500异常

image-20211204122349312

关闭URL PATH聚合

流控模式为链路模式时,sentinel 1.7.2以后版本,Sentinel Web过滤器默认会聚合所有URL的入口为sentinel_spring_web_context,
因此单独对指定链路限流会不生效,需要在application.yml添加如下语句来关闭URL PATH聚合
sentinel:
     web-context-unify: false  # 默认为true, 会将所有的请求链路聚合到sentinel_spring_web_context 链路下

熔断/降级

设置模拟环境

  • ProviderController 类中添加doSentinel04方法
    • 此方法中设置休眠,目的是为了演示慢调用(响应时间比较长)
     //AtomicLong 类支持线程安全的自增自减操作
    private AtomicLong atomicLong=new AtomicLong(1);
    @GetMapping("/sentinel04")
    public  String doSentinel04() throws InterruptedException {
        //获取自增对象的值,然后再加1
        long num=atomicLong.getAndIncrement();
        if(num%2==0){//模拟50%的慢调用比例
           Thread.sleep(200);
        }
        return "sentinel 04 test";
    }

满调用比例规则

  1. 服务启动后,选择要降级的链路

image-20211204122403548

  1. 设置熔断/降级的值
  • 表示熔断策略选择"慢调用比例",表示请求数超过3时,假如平均响应时间超过200毫秒的有30%,则对请求进行熔断,熔断时长为10秒钟,10秒以后恢复正常

image-20211204122415671

  1. 对指定链路进行刷新,多次访问测试,检测熔断效果
    • 熔断时间过后会自动启用服务

image-20211204122425565

Sentinel 异常处理模式

系统提供了默认的异常处理机制,假如默认处理机制不满足我们需求,我们可以自己进行定义。定义方式上可以直接或间接实现BlockExceptionHandler接口,并将对象交给spring管理
  1. 在方法四上进行更改, 模拟会有50%的几率报出异常
    //AtomicLong 类支持线程安全的自增自减操作
    private AtomicLong atomicLong=new AtomicLong(1);
    @GetMapping("/sentinel04")
    public  String doSentinel04() throws InterruptedException {
        //获取自增对象的值,然后再加1
        long num = atomicLong.getAndIncrement();
        if(num%2 == 0){//模拟50%的慢调用比例
//            Thread.sleep(200);

            throw new RuntimeException("出现异常");
        }
        return "sentinel 04 test";
    }
  1. 设置异常比例规则

image-20211204122435592

  • 当一秒内请求数超过两次并且报出异常的概率为30%以上, 就会进行熔断10秒
  1. 对指定链路进行刷新,多次访问测试,检测熔断效果
  2. image-20211204122444500

异常处理

系统提供了默认的异常处理机制,假如默认处理机制不满足我们需求,我们可以自己进行定义。
定义方式上可以直接或间接实现BlockExceptionHandler接口,并将对象交给spring管理。

自定义异常处理

  1. 新建Controller
package com.jt.provider.controller;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;


/*自定义降级异常处理对象*/

@Slf4j
@Component
public class ServiceBlockExceptionHandler implements BlockExceptionHandler {

    /*处理BlockException类型以及子类类型的异常
     *
     * */
    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       BlockException e) throws Exception {

        //设置响应数据编码
        response.setCharacterEncoding("utf-8");
        //告诉客户端响应数据的类型,以及客户端显示内容的编码
        response.setContentType("text/html;charset=utf-8");
        //向客户端响应一个json格式的字符串
        //String str="{\"status\":429,\"message\":\"访问太频繁了\"}";
        Map<String,Object> map=new HashMap<>();
        map.put("status", 429);
        map.put("message","访问太频繁了");
        String jsonStr=new ObjectMapper().writeValueAsString(map);
        PrintWriter out = response.getWriter();
        out.print(jsonStr);
        out.flush();
        out.close();
    }
}
  1. 新建service
package com.jt.provider.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;

@Service
public class ResourceService {

    /*
     * @SentinelResource使用此注解描述的方法,
     * 在此方法被访问时,会在sentinel的簇点链路中显示,
     * 此注解中指定的名字就是资源名,我们可以对这个资源
     * 的访问,按照指定的链路进行限流设计.
     *
     * 此注解中的blockHandlerClass用于指定,出现限流异常时的异常处理类,
     * blockHandler属性用于指定异常处理类中的方法(此方法的返回类型,参数
     * 要与 @SentinelResource注解描述的方法参数一致,可以加BlockException异常
     * 类型参数,而且方法必须是静态.)
     * fallbackClass 用于指定业务异常处理类,fallback用于指向业务处理类
     * 中的异常处理方法(此方法的返回类型,参数要与@SentinelResource注解描
     * 述的方法参数一致,可以加Throwable异常类型参数)
     * @return
     */
    @SentinelResource(value="doGetResource",
            blockHandlerClass = ResourceBlockHandler.class,
            blockHandler = "call",
            fallback = "call",
            fallbackClass = ResourceFallbackHandler.class)
    public String doGetResource(){
//        int a=100,b=0;
//        a=a/b;
        return "do get resource";
    }

}

package com.jt.provider.service;


import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class ResourceBlockHandler {

    /**
     * 注意此方法中的异常类型必须为BlockException (它是所有限流,降级等异常的父类类型)
     * @param ex
     * @return
     */
    public static String call(BlockException ex){
        log.error("block exception {}", ex.getMessage());
        return "访问太频繁了,稍等片刻再访问";
    }
}
  1. 设置异常比例降级策略
  2. 当我们访问有异常的方法4时, 就会使用自定义的异常信息

image-20211204122458511

  • 注意: 如果打印的异常信息是中文
    • 要设置相应数据编码
    • 要告诉浏览器响应数据的类型, 和客户端显示内容的编码

热点

热点参数限流会统计传入参数中的热点数据,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。
热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
其中,Sentinel会利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。

测试热点环境搭建

  1. Controller添加方法
    //http://localhost:8082/provider/sentinel/findById?id=10
    @GetMapping("/sentinel/findById")
    @SentinelResource("resource")
    public String doFindById(@RequestParam("id") Integer id){
        return "resource id is "+id;
    }
  1. 服务启动后,选择要限流的热点链路

image-20211204122510317

  1. 设置要限流的热点

image-20211204122520830

  • 热点规则的限流模式只有QPS模式(这才叫热点)。
  • 参数索引为@SentinelResource注解的方法参数下标,0代表第一个参数,1代表第二个参数。
  • 单机阈值以及统计窗口时长表示在此窗口时间超过阈值就限流。
  1. 多次访问热点参数方法,会进行限流

image-20211204122529676

  1. 特定参数设置, 编辑热点规则

image-20211204122541551

  • 添加参数类型,比如int
    • 参数值为5, 阈值为100
  • 当前端访问参数ID=5时, 会使用特定参数阈值为100的规则
    • 参数为其他值时, 会使用统一的阈值为1的规则
    • 可以添加多种类型的多种参数

系统规则

Sentinel的系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load(负载)、RT(响应时间)、入口 QPS 、线程数和CPU使用率五个维度监控应用数据,
让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
  1. 新增系统保护规则

image-20211204122557184

  • 系统规则是一种全局设计规则,其中
    • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5。
    • CPU使用率:当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)
    • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
    • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
    • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
  1. 使用CPU保护规则

image-20211204122607782

  • 当这个服务CPU使用率超过0.01, 就会限制所有的访问
  1. 前端访问方法一

image-20211204122616943

  1. 修改CPU值为0.1测试

image-20211204122638460

  1. 前端访问方法一

image-20211204122647345

  • 没有超过设置的CPU使用率范围, 不会触发系统保护规则

授权规则

根据调用方来限制资源是否通过, 使用 Sentinel 的授权规则的黑白名单控制的功能
  • 黑白名单根据资源的请求来源(origin)限制资源是否通过
  • 若配置白名单则只有请求来源位于白名单内时才可通过;
  • 若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。

测试授权规则的环境搭建

新建Controller类实现RequestOriginParser

package com.jt.provider.controller;


import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/*构建DefaultRequestOriginParser对象, 对请求数据进行解析
* 1.请求头
* 2.请求行
* 3.请求体 */

@Component
public class DefaultRequestOriginParser implements RequestOriginParser {

    /*当设置了授权规则后, 系统底层拦截到请求, 会调用此方法, 对请求数据进行解析
    * http://ip;port/path?参数名origin=xxx*/
    @Override
    public String parseOrigin(HttpServletRequest request) {

        String origin = request.getParameter("origin");
        return origin;
    }
}

设置授权规则

  1. 添加授权规则

image-20211204122705225

  1. 设置授权规则

image-20211204122714806

  1. 前端访问方法一,并传入参数

image-20211204122725311

image-20211204122735601

  • 当传入origin参数的值为app1和app2时,都会被拦截, 进行数据解析, 为黑名单数据拒绝通行
  • 当传入其他值时, 也会被底层RequestOriginParser拦截解析, 但是会放行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偶尔也吹晚风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值