Sentinel:分布式系统的流量防卫兵--CureGuy

目录

1、Sentinel概述

2、安装sentinel

2.1、下载sentinel的1.8.1版本

2.2、加载sentinel1.8.1版本的jar包

3、关于sentinel配置

3.1、pom.xml导入

3.2、bootstrap.yml配置

3.3、创建ProviderSentinelController 类

3.4、创建ResourceService类

3.5、sentinel入门 

3.6、设置限流策略

3.7、关联设置

3.8、链路设置 

4、降级设置

4.1、降级设置准备

4.1.1、编辑sentinel04方法

4.1.2、分析异常 创建DefaultRequestOriginParser类

4.1.3、创建ServiceBlockExceptionHandler类

4.2、选择要降级的资源04,进行配置新增。 

4.3、多次访问测试

4.4、热点设置

4.4.1、添加doFindById方法

4.4.2、刷新访问

4.4.3、新增热点设置

4.5、授权设置

4.5.1、创建RequestOriginParser接口的实现类

4.5.2、新增授权规则 

4.5.3、刷新访问localhost:8082/provider/sentinel01?origin=app2

5、拦截器

5.1、创建FrameworkTests类进行测试

5.2、测试结果

5.3、创建TimeInterceptor类


1、Sentinel概述

Sentinel:流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

流量控制:

        Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果进行资源调用。

熔断降级:

        通过并发线程数进行限制 和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。 通过响应时间对资源进行降级 除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。 

系统负载保护 :

        Sentinel 同时对系统的维度提供保护。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。 针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

Sentinel
隔离策略信号量隔离
熔断降级策略基于响应时间或失败比例
实时指标实现滑动窗口
规则配置支持多种数据源
扩展性多个扩展点
基于注解的支持支持注解
限流基于QPS,支持基于调用关系的限流
流量整形支持慢启动,匀速器模式
系统负载保护支持负载保护
控制台开箱即用,可配置规则,查看秒级监控,机器发现等
常见的价格适配Servlet,Spring Cloud,Dubbo,gRPC等

Sentinel两大核心:

核心库(Java 客户端):能够运行于所有 Java 运行时环境,同时对Dubbo /Spring Cloud 等框架也有较好的支持。

控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行。

2、安装sentinel

2.1、下载sentinel的1.8.1版本

sentinel 下载点我 sentinel和之前的依赖版本是有匹配度的,若版本太超前会导致不匹配发生冲突的问题,此处下载1.8.1版本即可。

2.2、加载sentinel1.8.1版本的jar包

在你的项目目录下新建目录sentinel,并在其下打开命令行操作,加载sentinel-dashboard-1.8.1.jar

java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar

3、关于sentinel配置

3.1、pom.xml导入

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

3.2、bootstrap.yml配置

    sentinel:
      transport: #随意制定一个未使用的端口号
        dashboard: localhost:8180 #制定当前sentinel控制台的地址
      eager: true #服务启动后就发送一个心跳信息
      web-context-unify: false
#注意sentinel和nacos属于同级 注意缩进

3.3、创建ProviderSentinelController 类

package com.jt.provider.controller;

import com.jt.provider.service.ResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/provider")
public class ProviderSentinelController {
    @RequestMapping("/sentinel01")
    public String doSentinel01(){
        return "sentinel 01 test ok!";
    }
    @RequestMapping("/sentinel02")
    public String doSentinel02(){
        return "sentinel 02 test ok!";
    }
    @Autowired
    private ResourceService resourceService;
    @RequestMapping("/sentinel03")
    public String doSentinel03(){
        resourceService.doGetResource();
        return "sentinel 03 test ok!";
    }
}

3.4、创建ResourceService类

package com.jt.provider.service;

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

@Service
public class ResourceService {
    @SentinelResource("doGetResource")
    public String doGetResource(){
        return "do get resource!";
    }
}

 启动服务器进入sentinel dashboard

3.5、sentinel入门 

启动sca-provider服务后对制定的服务进行访问

 刷新控制台查看实时监控

3.6、设置限流策略

选择需要限流的链路进行限流,设置限流策略

 找到制定的服务进行访问

反复刷新会出现如下,会有限流信息输出

 

3.7、关联设置

 sentinel的流控,设置关联

当刷新02时在1s内刷新01会出现如下限流信息出来

3.8、链路设置 

链路模式下得限流操作

 

 刷新一次出现如下,若反复刷新会报500错,表示被限流了,得等一等再次刷新即可

4、降级设置

4.1、降级设置准备

4.1.1、编辑sentinel04方法

 //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";
    }

    //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;
    }

4.1.2、分析异常 创建DefaultRequestOriginParser类

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;

/**
 * 构建RequestOriginParser对象,对请求数据进行解析
 * 1)请求行
 * 2)请求头
 * 3)请求体
 */
@Component
public class DefaultRequestOriginParser
        implements RequestOriginParser {
    /**
     * 当设置了授权规则后,系统底层拦截到请求,会调用此方法,对请求数据进行解析
     * httpServletRequest
     * http://ip:port/path?origin=aaa
     */
    @Override
    public String parseOrigin(HttpServletRequest request) {
        String origin=request.getParameter("origin");
        return origin;
    }
}

4.1.3、创建ServiceBlockExceptionHandler类

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();
    }
}

4.2、选择要降级的资源04,进行配置新增。 

4.3、多次访问测试

 

4.4、热点设置

4.4.1、添加doFindById方法

    //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;
    }

4.4.2、刷新访问

4.4.3、新增热点设置

4.5、授权设置

4.5.1、创建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;

/**
 * 构建RequestOriginParser对象,对请求数据进行解析
 * 1)请求行
 * 2)请求头
 * 3)请求体
 */
@Component
public class DefaultRequestOriginParser
        implements RequestOriginParser {
    /**
     * 当设置了授权规则后,系统底层拦截到请求,会调用此方法,对请求数据进行解析
     * httpServletRequest
     * http://ip:port/path?origin=aaa
     */
    @Override
    public String parseOrigin(HttpServletRequest request) {
        String origin=request.getParameter("origin");
        return origin;
    }
}

4.5.2、新增授权规则 

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

4.5.3、刷新访问localhost:8082/provider/sentinel01?origin=app2

 

 

 当把app2从授权规则中去除则可以访问

5、拦截器

5.1、创建FrameworkTests类进行测试

package com.jt.common.interceptor;

import java.time.LocalTime;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/*
* 如何理解框架?设计好一个半成品(类似模板)
* 框架设计时会有一些对象的定义以及这些对象的执行流程,类似一个执行链
* */
//定义一个拦截器对象的接口
interface  HandlerInterceptor{
    default void before(){}
    default void after(){}
}
//处理器接口
interface Handler{
    void processed();//处理业务的方法
}
//定义一个执行链
class  ExecutionChain{//我是执行链的设计者
    private List<HandlerInterceptor> interceptors=new CopyOnWriteArrayList<>();//拦截器
    //new CopyOnWriteArrayList<>()确保线程安全
    private Handler handler;//处理器
    public ExecutionChain(List<HandlerInterceptor> interceptors,Handler handler){
        this.handler=handler;
        this.interceptors.addAll(interceptors);}//此构造方法 给上面类里属性赋值传参
    public  void  execute(){
        //负责执行业务的方法(处理请求,不考虑参数...)
        //1.before
        for (int i = 0; i <interceptors.size() ; i++) {
            interceptors.get(i).before();
        }
        //2.processed
        handler.processed();
        //3.after
        for (int i = interceptors.size()-1; i >=0 ; i--) {
            interceptors.get(i).after();
        }
    }
}
public class FrameworkTests {
    public static void main(String[] args) {
        //创建执行链和执行链对象
        List<HandlerInterceptor> interceptors=new CopyOnWriteArrayList<>();
        interceptors.add(new HandlerInterceptor() {
            @Override
            public void before() {
                System.out.println("记录考试开始时间"+ LocalTime.now());
            }
            @Override
            public void after() {
                System.out.println("考试结束时间:"+LocalTime.now());
            }
        });
        ExecutionChain chain=new ExecutionChain(interceptors, new Handler() {
            @Override
            public void processed() {
                System.out.println("开始考试");
            }
        });
        //执行执行链
        chain.execute();
    }
}

5.2、测试结果

 5.3、创建TimeInterceptor类

package com.jt.provider.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalTime;


public class TimeInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                              HttpServletResponse response,
                              Object handler)throws  Exception{
        System.out.println("=====拦截器已运行=====");

        LocalTime now =LocalTime.now();//获取当前时间
        int hour =now.getHour();//获取当前时间的小时单位
        if (hour <8||hour>=21)
            throw  new RuntimeException("请在8~21点之间访问");
        return true;
    }

创建SpringWebConfig类

package com.jt.provider;

import com.jt.provider.interceptor.TimeInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class SpringWebConfig implements WebMvcConfigurer {

    public  void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(new TimeInterceptor())
                .addPathPatterns("/provider/sentinel01");
    }
}

对01方法进行拦截(把时间改了if (hour <8||hour>=12))

 把时间改了(hour <8||hour>=21)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值