nacos(八): sentinel——基本使用

一、概要

在微服务的架构中,流控是一个重要的任务。sentinel是阿里开源的流量治理组件,针对访问的“资源”或服务路径进行流控,内置了限流、熔断及系统负载保护等功能。

sentinel分为系统库及控制面板(也称“控制台")两个部分。其中,控制台能运行于java 8及以上版本,不依赖于其它三方资源;而控制面板则是sentinel的管理中心,用户可通过图形化界面对规则进行管理和配置。

 

二、下载sentinel控制面板

Sentinel官网地址:https://sentinelguard.io/zh-cn/index.html
Sentinel项目地址:https://github.com/alibaba/Sentinel

当前版本1.8.8:

 

三、启动sentinel

1) 一般启动:

java -jar sentinel-dashboard-1.8.8.jar

2) 带参数启动:

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.8.jar

其中:

-Dserver.port=8080:指定Sentinel控制台程序的端口为8080。
-Dcsp.sentinel.dashboard.server=localhost:8080:Sentinel控制台的访问地址,客户端会自动向该地址发送心跳包。
-Dproject.name=sentinel-dashboard:指定Sentinel控制台程序显示的名称。

3) 带参数启动:

nohup java -server -Xms64m -Xmx256m -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=192.168.66.100:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.8.jar >> /opt/sentinel.log 2>&1 &

启动成功后 ,在浏览器访问http://127.0.0.1:8080,即可看到sentinel的管理界面。并输入用户名sentinel和密码sentinel,即可进入管理,如下图:

 

四、配置项目与sentinel进行通信

当前将多模块项目中的producer(看这里)进行扩展,集成sentinel。

1)在pom.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>com.example</groupId>
        <artifactId>multimod_nacos</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>producer</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <!--springboot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 服务发现(生产者)  -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

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

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.example.producer.ProducerApplication</mainClass>
                    <skip>false</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
复制代码

2)配置application.yml

复制代码
server:
  port: 8085


spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
      config:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
        namespace: public

    loadbalancer:
      nacos:
        enabled: true

    sentinel:
      transport:
        port: 8719
        dashboard: 127.0.0.1:8080

  application:
    name: product1
复制代码

配置完成后,启动producer。访问producer中的资源/hello即可在sentinel面板中找到对就的模块。

注意:因为sentinel是lazyload模式,所以单纯的producer启动成功sentinel是不显示的。只有访问了项目的资源,sentinel才会显示对应的项目模块。

 

五、规则配置

在“链路规则”菜单中,可以看到访问过的资源。在资源右侧,可以流控、熔断、热点和授权四种规则。

 关于这四种规则的详细配置,打开设置面版一目了解,就不在此一一赘述,如果感兴趣的小伙伴可查看这里(点击查看)

在使用的过程中,会遇到以下问题:如何对资源进行通配符限制?关于这个问题,只需要在项目中添加一个UrlCleaner类,就可以对访问的url进行规整并以通配符的形式传给sentinel:

 

6、自定义限流方法

 1) 针对单个资源自定义限流方法

先定义一个处理限流的类,类内部定义自定义限流方法:

复制代码
package com.example.producer.component;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class GlobalBlockHandler {
    public static String handleBlock(String id,BlockException ex) throws IOException {
        return "Global block handler: " + ex.getMessage();
    }

    public static String handleFlow(String id, Throwable ex) throws IOException {
        return "Global flow handler: " + ex.getMessage();
    }
}
复制代码

再用@SentinelResource注解标注对应的类资源:

复制代码
@RestController
public class HelloController {

    @RequestMapping("/hello")
    @SentinelResource(value = "hello",
            fallback = "handleFlow",
            fallbackClass = com.example.producer.component.GlobalBlockHandler.class,
            blockHandler = "handleBlock",
            blockHandlerClass = com.example.producer.component.GlobalBlockHandler.class)
    public String Hello(String id){

        return "hello world "+id;
    }


}
复制代码

这里要注意的是,自定义限流方法的参数,一定要跟controller里资源方法一致。

另外,需要重点注意的是,在sentinel控制面板内限流设置的时候,要使用资源名称去限流,自定义的限流方法才会生效;如果使用路径限流,自定义限流不生效。

2)自定义全局限流方法 

复制代码
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
​
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        log.info("UrlBlockHandler.....................................");
        // 自定义封装的类,可以定义
        Result restObject = null;
​
        if (e instanceof FlowException) {
            // 限流
            restObject = ResultUtils.wrapFail(5001,"接口限流");
        } else if (e instanceof DegradeException) {
            // 降级
            restObject = ResultUtils.wrapFail(5002,"服务降级");
        } else if (e instanceof ParamFlowException) {
            // 热点参数
            restObject = ResultUtils.wrapFail(5003,"热点参数限流");
        } else if (e instanceof SystemBlockException) {
            // 系统保护
            restObject = ResultUtils.wrapFail(5004,"触发系统保护规则");
        } else if (e instanceof AuthorityException) {
            // 授权规则
            restObject = ResultUtils.wrapFail(5005,"授权规则不通过");
        }
​
        //返回json数据
        response.setStatus(200);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        //springmvc 的一个json转换类 (jackson)
        new ObjectMapper().writeValue(response.getWriter(), restObject);
    }
}
复制代码

重点注意:只有对路径进行限流设置,全局的限流方法才能生效;如果是针对资源名称进行限流设置,全局限流方法不被触发。

3)全局系统异常实现全局自定义限流方法

复制代码
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
 
import java.util.HashMap;
import java.util.Map;
 
 
@RestControllerAdvice
public class CustomExceptionHandler {
 
    /**
     * 限流全局异常
     */
    @ExceptionHandler(FlowException.class)
    public Map handlerFlowException(){
        return new HashMap(){{
            put("code", HttpStatus.TOO_MANY_REQUESTS.value());
            put("msg", "被限流");
        }};
    }
 
    /**
     * 熔断全局异常
     */
    @ExceptionHandler(DegradeException.class)
    public Map handlerDegradeException(){
        return new HashMap(){{
            put("code", HttpStatus.TOO_MANY_REQUESTS.value());
            put("msg", "被熔断");
        }};
    }
 
    /**
     * 热点限流异常
     */
    @ExceptionHandler(ParamFlowException.class)
    public Map handlerparamFlowException(){
        return new HashMap(){{
            put("code", HttpStatus.TOO_MANY_REQUESTS.value());
            put("msg", "热点限流");
        }};
    }
 
    /**
     *  Sentinel 权限拦截全局异常
     */
    @ExceptionHandler(AuthorityException.class)
    @ResponseBody
    public Map handlerAuthorityException(){
        return new HashMap(){{
            put("code", HttpStatus.UNAUTHORIZED.value());
            put("msg", "暂无权限");
        }};
    }
}
复制代码

重点注意的是,在sentinel控制面板内限流设置的时候,要使用资源名称去限流,全局系统异常自定义的限流方法才会生效;如果使用路径限流,则不生效。

 

好了,到这里sentinel的基本使用以及自定义的限流方法已进行了较为详细的讨论。下一篇,让我们一起了解sentinel规则的持久化:)

 

posted on   咚..咚  阅读(181)  评论(0编辑  收藏  举报

努力加载评论中...

导航

点击右上角即可分享
微信分享提示