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 還能實現控制規則的實時修改、遠程配置、狀態監控等等,它是個非常強大的框架。