当前位置 博文首页 > 2926143939:sentinel-实战

    2926143939:sentinel-实战

    作者:2926143939 时间:2021-01-21 18:04

    sentinel-实战笔记

    什么是Sentinel

    Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。

    Sentinel主要特性:
    在这里插入图片描述

    获取Sentinel

    控制台(下载地址在这里)

    部署

    在使用Sentinel之前,我们首先需部署Sentinel Dashborad,通过以下命令运行

    java -Dserver.port=9999 -Dcsp.sentinel.dashboard.server=localhost:9999 -Dproject.name=sentinel-dashboard -jar D:\server\sentinel\sentinel-dashboard-1.7.0.jar
    

    启动成功可以访问:http://localhost:9999

    在这里插入图片描述

    默认账号密码:sentinel/sentinel

    登录后可以看到dashboard

    在这里插入图片描述

    此时可以当sentinel监控到当前自己服务的信息。我们可以启动自己的应用。

    项目中使用Sentinel

    Sentinel针对各个主流框架都提供了适配(包括Servlet,Dubbo,SpringBoot/SpringCloud,gRPC,RocketMQ等),本文以SpringBoot2举例(通过笔者测试发现,SpringBoot 1.x支持不好,自定义流控规则不可用)。

    配置application.yml

    首先我们需要在SpringBoot2的配置文件中指定Sentinel连接的控制台地址和项目名,即application.yml文件,如下

    spring:
      application:
        name: sentinel-project
      cloud:
        sentinel:
          transport:
            dashboard: localhost:9999
    

    配置pom.xml

    <!--sentinel-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!--sentinel end-->
    

    此时import依赖你会发现报错:

    Could not find artifact com.alibaba.csp:sentinel-web-servlet:pom:unknown in nexus-aliyun (http://maven.aliyun.com/nexus/content/groups/public)
    

    需要在pom文件中添加如下配置即可:

    <dependencyManagement>
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-alibaba-dependencies</artifactId>
    			<version>0.2.2.RELEASE</version>
    			<type>pom</type>
    			<scope>import</scope>
    		</dependency>
    	</dependencies>
    </dependencyManagement>
    

    开发控制器

    开发一个控制器用于测试。

    @RestController
    @RequestMapping("/sen")
    public class HelloController {
    
        @RequestMapping("/hello")
        public String hello() {
            return "success";
        }
    }
    

    部署项目

    至此,启动项目。观察sentinel后台:
    在这里插入图片描述

    可以看到我们的应用被sentinel拦截,链路已被追踪到。

    Sentinel操作

    流控规则

    直接限流:直接对关联的url资源限流

    开启sentinel,开启provider服务

    对/index资源做流控,设置QPS为1(表示一秒钟只允许访问一次)

    在这里插入图片描述

    此时我们短时间内多次访问http://localhost:7788/sen/hello接口,观察返回结果:

    在这里插入图片描述

    出现Blocked by Sentinel (flow limiting)很幸运,我们成功了!!!说明我们的接口被拦截了。

    但是我们思考一个问题,在现在前后端分离的开发模式下,这样的异常抛给前端,肯定是不合适的!这时我们可以自定义异常来处理这个问题。

    自定义URL拦截异常

    /**
     * 自定义sentinel异常返回信息
     * @author user
     */
    @Component
    public class CustomUrlBlockHandler implements UrlBlockHandler {
        @Override
        public void blocked(HttpServletRequest request,
                            HttpServletResponse response,
                            BlockException e) throws IOException {
            R r = null;
            // BlockException 异常接口,其子类为Sentinel五种规则异常的实现类
            // AuthorityException 授权异常
            // DegradeException 降级异常
            // FlowException 限流异常
            // ParamFlowException 参数限流异常
            // SystemBlockException 系统负载异常
            if (e instanceof FlowException) {
                r = R.error(100, "访问速度过快");
            } else if (e instanceof DegradeException) {
                r = R.error(100, "接口已被降级,暂时无法访问");
            } else if (e instanceof AuthorityException) {
                r = R.error(100, "无权访问");
            } else if (e instanceof ParamFlowException) {
                r = R.error(100, "热点参数限流了");
            } else if (e instanceof SystemBlockException) {
                r = R.error(100, "系统靠不住了,稍等吧");
            }
            response.setStatus(500);
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-type","application/json;charset=utf-8");
            response.setContentType("application/json;charset=utf-8");
            new ObjectMapper().writeValue(response.getWriter(), r);
        }
    }
    

    实现UrlBlockHandler接口,重写blocked方法,对BlockException子异常进行处理。

    重启项目再次访问:

    在这里插入图片描述

    这样抛给前端的异常就比较友好了。

    降级规则

    RT: 单个请求的响应时间超过阈值,则进入准降级状态,接下来 1 S 内连续 5 个请求响应时间均超过阈值,就进行降级,持续时间为时间窗口的值。

    异常比例:每秒异常数量占通过量的比例大于阈值,就进行降级处理,持续时间为时间窗口的值。

    异常数:1 分钟内的异常数超过阈值就进行降级处理,时间窗口的值要大于 60S,否则刚结束熔断又进入下一次熔断了。

    热点规则

    热点规则是流控规则的更细粒度操作,可以具体到对某个热点参数的限流,设置限流之后,如果带着限流参数的请求量超过阈值,则进行限流,时间为统计窗口时长。

    必须要添加@SentinelResource,即对资源进行流控。

    定义接口

    @GetMapping("/hot")
    @SentinelResource("hot")
    public R hot(
            @RequestParam(value = "num1", required = false) Integer num1,
            @RequestParam(value = "num2", required = false) Integer num2) {
        log.info("num1:{}, num2:{}", num1, num2);
        return R.ok();
    }
    

    配置热点参数

    在这里插入图片描述

    访问

    在这里插入图片描述

    num1参数被携带多次访问接口,抛出以上异常。

    定义全局异常

    发现该异常没用被捕获,我们定义全局异常处理器来处理。

    @Slf4j
    @Component
    @RestControllerAdvice
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class GlobalExceptionHandler {
    
        /**
         * 功能描述: 处理ParamFlowException<br>
         * @param ex
         * @return: {@link R}
         * @Author: Edward
         * @Date: 2021/1/20 10:13
         */
        @ExceptionHandler(value = ParamFlowException.class)
        protected R handleParamFlowException(ParamFlowException ex) {
            //获取所有错误信息
            return R.error(4000,"热点参数限流了");
        }
    }
    

    再次访问,返回结果如下:
    在这里插入图片描述

    授权规则

    给指定的资源设置流控应用(追加参数),可以对流控应用进行访问权限的设置,具体就是添加白名单和黑名单。

    添加配置类

    如何给请求指定流控应用,通过实现RequestOriginParser接口来完成,代码如下所示。

    public class RequestOriginParserDefinition implements RequestOriginParser {
        @Override
        public String parseOrigin(HttpServletRequest httpServletRequest) {
            String serviceName = httpServletRequest.getParameter("appType");
            return serviceName;
        }
    }
    

    注册配置类

    RequestOriginParserDefinition类交给Spring容器关联。

    /**
     * @version 1.0
     * @Author: Edward
     * @Date: 2021/1/21 15:21
     * @Description:
     */
    @Configuration
    public class SentinelConfiguration {
        @PostConstruct
        public void init() {
            WebCallbackManager.setRequestOriginParser(new RequestOriginParserDefinition());
        }
    }
    

    配置规则

    在这里插入图片描述

    我们配置值运行应用类型为pc应用源可以访问。

    访问

    当以http://localhost:7788/sen/hello?appType=pc访问,

    在这里插入图片描述

    此时可以正常访问。

    我们更改appType,再次访问http://localhost:7788/sen/hello?appType=app
    在这里插入图片描述

    存中…(img-wjogFRIm-1611222474344)]

    我们配置值运行应用类型为pc应用源可以访问。

    访问

    当以http://localhost:7788/sen/hello?appType=pc访问,

    [外链图片转存中…(img-akAWxZ6L-1611222474345)]

    此时可以正常访问。

    我们更改appType,再次访问http://localhost:7788/sen/hello?appType=app

    [外链图片转存中…(img-1v9XwvpR-1611222474346)]

    此时接口已被拦截,无法访问。

    源码:https://gitee.com/edwarder/sentinel-project.git