1

Alibaba Sentinel 是一个灵活的系统负载控制框架,通过控制接口和方法的调用来保证系统负载不会过大,维持正常响应速度。

该项目的地址是 https://github.com/alibaba/Se... 。但是阿里的文档一贯看起来一头雾水,所以本文介绍如何用一个最简单的项目来上手。如果你熟悉 Spring Boot,那么几分钟就可以搞定。

1、创建一个 Maven 项目

首先创建一个空的 Maven 项目,加上 Spring Boot 的依赖。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 
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.demo</groupId>
  <artifactId>sentinel-test</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.1.3.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

</project>

这里没有将 Spring Boot 作为 parent 项目,而是使用 <dependencyManagement>,但效果是一样的。

2、添加依赖关系

pom.xml 中,首先添加 Spring Boot 依赖:

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

然后添加 Sentinel。在这个例子当中,我们将用 注解 来实现负载控制,所以添加 sentinel-annotation-aspectj 依赖:

<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-annotation-aspectj</artifactId>
  <version>1.5.1</version>
</dependency>

添加了这两个依赖就 OK 了。

3、启动类

Spring Boot 项目需要一个 main() 方法来启动,我们命名这个类为 com.demo.SentinelTestApplication,其内容如下:

@SpringBootApplication
public class SentinelTestApplication {
  public static void main(String[] args) throws Exception {
    SpringApplication.run(SentinelTestApplication.class, args);
  }
}

目前这个类还没有具体的内容,但我们应该先运行一下,确保前面做的事情没有出错,然后再添加内容。

4、需要进行访问控制的服务 DemoService

我们在 com.demo 包下创建一个名为 DemoService 的类,这个类包含一个需要做访问控制的 call() 方法:

@Service
public class DemoService {

  private int counter;

  @SentinelResource(value = "DemoService.call", blockHandler = "callBlocked")
  public void call() {
    System.out.println("Hello (" + ++counter + ")");
  }

  public void callBlocked(BlockException ex) {
    System.err.println("Blocked (" + ++counter + ") : " + ex.toString());
  }
}

所谓访问控制就是当某个方法调用过于频繁时,拒绝掉一部分调用。什么才叫过于频繁,我们可以通过自定义控制规则的方式来告诉 Sentinel。定义控制规则的部分放在后面介绍,我们现在先关注业务本身,也就是 DemoService 类。

这个类包含两个方法,其中 call() 方法是主角,正常的业务会调用这个方法;而 callBlocked() 则会在 call() 方法被拒绝掉时调用。

call() 方法上面的 @SentinelResource 注解标明了该方法是需要进行访问控制的。Sentinel 将需要进行访问控制的方法都称作资源。这个注解有两个属性,value 属性表示该资源的名称,我们通过名称为不同的资源制定不同的控制规则。blockHandler 属性表示方法被拒绝时应该调用哪个替代方法,这个替代方法必须在同一个类当中,且参数列表要在原方法参数列表的基础上再添加一个 BlockException 类型的参数。

5、编写控制规则

Sentinel 将控制规则包装为 com.alibaba.csp.sentinel.slots.block.flow.FlowRule 类。它包含下面几个属性:

  • resource : 该规则针对哪个资源;
  • grade : 从哪个方面进行度量,如该方法的每秒调用次数,或同时调用该方法的线程数等等。
  • count : 度量阈值。超过这个阈值则会拒绝调用该方法。
  • strategy : 多个规则之间的搭配策略,具体参考这里

下面我们在 SentinelTestApplication 类里面添加一个创建规则的方法,同时在 main() 方法里面初始化它:

  private static void initRules() throws Exception {
    FlowRule rule1 = new FlowRule();
    rule1.setResource("DemoService.call");
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule1.setCount(5);   // 每秒调用最大次数为 5 次

    List<FlowRule> rules = new ArrayList<>();
    rules.add(rule1);
    
    // 将控制规则载入到 Sentinel
    com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager.loadRules(rules);  
  }

  public static void main(String[] args) throws Exception {
    initRules();  // Sentinel 载入规则不一定非要在 Spring 初始化之前,在这之后也可以。
    SpringApplication.run(SentinelTestApplication.class, args);
  }

这样 Sentinel 的规则就设置完毕。

6、启用 Sentinel 注解的 AOP 拦截

Spring 提供 AOP 机制来实现方法调用的拦截,这是 Sentinel 实现控制规则的原理。Sentinel 提供 com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect 类,我们要在 Spring 容器中加入这个 bean 才能让 @SentinelResource 注解起作用。我们需要在 SentinelTestApplication 类里面添加下面的代码:

  @Bean
  public SentinelResourceAspect sentinelResourceAspect() {
    return new SentinelResourceAspect();
  }

当然,在实际项目里面这一步可以放到自动配置当中。

7、测试控制规则

最后我们写一个方法来测试控制规则是否起作用,同样是在 SentinelTestApplication 类里面:

  @Autowired
  private DemoService demoService;

  @PostConstruct
  public void run() {
    for (int i = 0; i < 10; i++) {
      demoService.call();
    }
  }

实际运行 main() 方法时,你将会看到这样的输出:

Hello (1)
Hello (2)
Hello (3)
Hello (4)
Hello (5)
Blocked (6) : com.alibaba.csp.sentinel.slots.block.flow.FlowException
Blocked (7) : com.alibaba.csp.sentinel.slots.block.flow.FlowException
Blocked (8) : com.alibaba.csp.sentinel.slots.block.flow.FlowException
Blocked (9) : com.alibaba.csp.sentinel.slots.block.flow.FlowException
Blocked (10) : com.alibaba.csp.sentinel.slots.block.flow.FlowException

通过这个例子,你应该大概了解 Sentinel 运作的机制了。在这个基础上,Sentinel 还能实现控制规则的实时修改、远程配置、状态监控等等,它是个非常强大的框架。


捏造的信仰
2.8k 声望272 粉丝

Java 开发人员