SpringCloud Alibaba Sentinel 從入門到精通
前言
在微服務(wù)架構(gòu)中,服務(wù)間的依賴關(guān)系復(fù)雜,一個(gè)服務(wù)的故障可能引發(fā)連鎖反應(yīng),導(dǎo)致整個(gè)系統(tǒng)雪崩。Sentinel 作為阿里巴巴開源的流量控制框架,能從流量控制、熔斷降級(jí)等維度保護(hù)服務(wù)穩(wěn)定性。本文將從實(shí)戰(zhàn)角度,完整講解 Sentinel 的核心概念、使用方式及各類規(guī)則配置。
一、Sentinel 核心概念
1.1 什么是 Sentinel
Sentinel(分布式系統(tǒng)的流量防衛(wèi)兵)以流量為切入點(diǎn),提供流量控制、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)等能力,保障微服務(wù)高可用。
1.2 核心概念
- 資源:Sentinel 要保護(hù)的對(duì)象,可是一個(gè)接口、方法、服務(wù)等。
- 規(guī)則:定義保護(hù)資源的策略,包括流量控制、熔斷降級(jí)、熱點(diǎn)參數(shù)、系統(tǒng)規(guī)則、授權(quán)規(guī)則等。
- 核心功能:
- 流量控制:限制接口 QPS / 線程數(shù),避免服務(wù)被壓垮。
- 熔斷降級(jí):當(dāng)下游服務(wù)異常時(shí),暫時(shí)切斷調(diào)用,防止級(jí)聯(lián)故障。
二、環(huán)境準(zhǔn)備
2.1 搭建基礎(chǔ)微服務(wù)
2.1.1 服務(wù)提供者(sentinel-provider)
application.yml
server:
port: 9090
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.209.129:8848
application:
name: sentinel-provider核心服務(wù)類
@Service
public class UserServiceImpl implements UserService {
@Override
public User getUserById(Integer id) {
// 模擬網(wǎng)絡(luò)延時(shí)
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new User(id,"王糞堆-provider",18);
}
}2.1.2 Feign 接口(sentinel_feign)
@FeignClient("sentinel-provider")
public interface UserFeign {
@RequestMapping(value = "/provider/getUserById/{id}")
public User getUserById(@PathVariable Integer id);
}
2.1.3 服務(wù)消費(fèi)者(sentinel_consumer)
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">
<parent>
<artifactId>springcloud_parent</artifactId>
<groupId>com.hg</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel_consumer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.hg</groupId>
<artifactId>springcloud_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--feign接口-->
<dependency>
<groupId>com.hg</groupId>
<artifactId>sentinel_feign</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--Sentinel核心依賴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
</project>application.yml
server:
port: 8080
tomcat:
max-threads: 10 # 降低tomcat并發(fā),便于測(cè)試雪崩
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.209.129:8848
sentinel:
transport:
dashboard: 127.0.0.1:8080 # Sentinel控制臺(tái)地址
feign:
client:
config:
default:
connectionTimeout: 5000
readTimeout: 5000
sentinel:
enabled: true # 開啟Feign整合Sentinel三、Sentinel 快速入門
3.1 方式 1:硬編碼(拋異常方式)
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@RequestMapping(value = "/hello")
public String hello() {
Entry entry = null;
try {
// 定義資源
entry = SphU.entry("/consumer/hello");
return "Hello Sentinel?。?!";
} catch (BlockException e) {
// 限流兜底邏輯
return "接口被限流了, exception: " + e;
}finally {
if (entry != null) {
entry.exit();
}
}
}
// 初始化限流規(guī)則
@PostConstruct
public void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource("/consumer/hello"); // 資源名
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS); // 按QPS限流
rule1.setCount(2); // QPS閾值2
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
}3.2 方式 2:注解方式(推薦)
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
// 開啟Sentinel注解支持
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
return new SentinelResourceAspect();
}
@RequestMapping(value = "/hello2")
@SentinelResource(value="/consumer/hello2",blockHandler = "blockHandlerMethod")
public String hello2() {
return "Hello Sentinel2!??!";
}
// 限流兜底方法
public String blockHandlerMethod(BlockException e){
return "接口被限流了, exception: " + e;
}
@PostConstruct
public void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource("/consumer/hello2");
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setCount(2);
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
}3.3 Sentinel 控制臺(tái)使用
3.3.1 啟動(dòng)控制臺(tái)
# 下載地址:https://github.com/alibaba/Sentinel/releases java -jar sentinel-dashboard-1.8.1.jar
訪問 http://localhost:8080,默認(rèn)賬號(hào) / 密碼:sentinel/sentinel。
3.3.2 接入控制臺(tái)
消費(fèi)者配置文件中添加:
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080訪問任意接口(如 http://127.0.0.1:8080/consumer/hello3),控制臺(tái)即可識(shí)別服務(wù)。
四、Sentinel 核心規(guī)則配置
4.1 流量控制規(guī)則
流量控制是 Sentinel 最核心的功能,通過限制 QPS / 線程數(shù),防止服務(wù)被壓垮。
4.1.1 核心配置項(xiàng)說明
| 配置項(xiàng) | 說明 |
|---|---|
| 資源名 | 唯一標(biāo)識(shí),默認(rèn)請(qǐng)求路徑 |
| 針對(duì)來源 | 限制調(diào)用方(默認(rèn) default,不區(qū)分來源) |
| 閾值類型 | QPS(每秒請(qǐng)求數(shù))/ 線程數(shù) |
| 流控模式 | 直接(限流當(dāng)前接口)/ 關(guān)聯(lián)(關(guān)聯(lián)接口閾值觸發(fā)限流)/ 鏈路(指定入口限流) |
| 流控效果 | 快速失敗 / Warm Up(預(yù)熱)/ 排隊(duì)等待 |
4.1.2 典型場(chǎng)景配置
(1)QPS 限流
- 規(guī)則配置:資源名
/consumer/getUserById/{id},閾值類型 QPS,單機(jī)閾值 2; - 效果:接口 QPS 超過 2 時(shí),直接觸發(fā)限流。
(2)Warm Up(預(yù)熱限流)
- 適用場(chǎng)景:流量突增(如秒殺),避免瞬間打滿服務(wù);
- 規(guī)則配置:閾值類型 QPS,單機(jī)閾值 6,預(yù)熱時(shí)長(zhǎng) 5 秒;
- 效果:QPS 從 2(6/3)開始,5 秒后升至 6,平滑提升流量處理能力。
(3)排隊(duì)等待
- 適用場(chǎng)景:需要?jiǎng)蛩偬幚碚?qǐng)求(如削峰填谷);
- 規(guī)則配置:閾值類型 QPS,單機(jī)閾值 1,排隊(duì)超時(shí)時(shí)間 10ms;
- 效果:請(qǐng)求勻速通過,超時(shí)未處理的請(qǐng)求直接丟棄。
4.2 熱點(diǎn)參數(shù)限流
對(duì)接口參數(shù)做精細(xì)化限流,支持參數(shù)例外項(xiàng)(如特定 ID 放寬閾值)。
@RequestMapping(value = "/getUserById/{id}")
@SentinelResource(value = "getUserById", blockHandler = "blockHandlerMethod")
public User getUserById(@PathVariable Integer id) {
return userFeign.getUserById(id);
}
// 熱點(diǎn)參數(shù)限流兜底方法
public User blockHandlerMethod(Integer id, BlockException e) {
return new User(id, "熱點(diǎn)參數(shù)限流觸發(fā)", 0);
}- 規(guī)則配置:資源名
getUserById,參數(shù)索引 0(第一個(gè)參數(shù)),單機(jī)閾值 2; - 例外項(xiàng)配置:參數(shù)值 2,閾值 3(ID=2 時(shí) QPS 閾值提升至 3)。
4.3 熔斷降級(jí)規(guī)則
當(dāng)接口響應(yīng)慢 / 異常比例高時(shí),暫時(shí)切斷調(diào)用,避免級(jí)聯(lián)故障。
4.3.1 三種熔斷策略
| 策略 | 觸發(fā)條件 |
|---|---|
| 慢調(diào)用比例 | 慢調(diào)用(RT 超過閾值)占比超過設(shè)定值,且請(qǐng)求數(shù)≥最小請(qǐng)求數(shù) |
| 異常比例 | 異常請(qǐng)求占比超過設(shè)定值,且請(qǐng)求數(shù)≥最小請(qǐng)求數(shù) |
| 異常數(shù) | 異常請(qǐng)求數(shù)超過設(shè)定值,且請(qǐng)求數(shù)≥最小請(qǐng)求數(shù) |
4.3.2 配置示例(慢調(diào)用比例)
- 規(guī)則配置:資源名
/consumer/getUserById/{id},最大 RT 200ms,比例閾值 0.5,熔斷時(shí)長(zhǎng) 5s,最小請(qǐng)求數(shù) 5; - 效果:5 個(gè)請(qǐng)求中若 50% 以上 RT 超過 200ms,觸發(fā)熔斷,5 秒內(nèi)拒絕所有請(qǐng)求。
4.4 授權(quán)規(guī)則
基于請(qǐng)求來源做黑白名單控制,適合接口訪問權(quán)限管控。
4.4.1 實(shí)現(xiàn)來源解析
@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
// 從請(qǐng)求參數(shù)獲取來源標(biāo)識(shí)(可替換為請(qǐng)求頭、Session等)
return request.getParameter("origin");
}
}4.4.2 規(guī)則配置
- 黑名單:資源名
/consumer/getUserById/{id},黑名單值app1; - 效果:來源為
app1的請(qǐng)求直接被拒絕。
4.5 系統(tǒng)規(guī)則
針對(duì)整個(gè)應(yīng)用的全局規(guī)則(粒度粗,慎用),支持:
- LOAD(Linux 系統(tǒng)負(fù)載);
- RT(所有請(qǐng)求平均響應(yīng)時(shí)間);
- 線程數(shù)(所有請(qǐng)求總線程數(shù));
- 入口 QPS(所有接口總 QPS);
- CPU 使用率。
五、Sentinel 高級(jí)特性
5.1 自定義兜底邏輯(blockHandler)
5.1.1 同級(jí)別兜底(當(dāng)前類)
@SentinelResource(value = "getUserById", blockHandler = "blockHandlerMethod")
public User getUserById(@PathVariable Integer id) {
return userFeign.getUserById(id);
}
// 兜底方法(參數(shù)與原方法一致,最后加BlockException)
public User blockHandlerMethod(Integer id, BlockException e) {
return new User(0, "接口被流控/熔斷:"+e, 0);
}5.1.2 外置兜底類(解耦)
// 外置兜底類(方法必須static)
public class BlockHandlerClass {
public static User blockHandlerMethod(Integer id, BlockException e) {
return new User(0, "外置兜底:"+e, 0);
}
}
// 使用外置兜底類
@SentinelResource(value = "getUserById",
blockHandler = "blockHandlerMethod",
blockHandlerClass = BlockHandlerClass.class)
public User getUserById(@PathVariable Integer id) {
return userFeign.getUserById(id);
}5.2 全局異常處理
統(tǒng)一處理 Sentinel 各類異常,返回標(biāo)準(zhǔn)化響應(yīng)。
@Component
public class GlobalBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
response.setContentType("application/json;charset=utf-8");
Result data = null;
if (e instanceof FlowException) {
data = new Result(-1, "限流異常");
} else if (e instanceof DegradeException) {
data = new Result(-2, "降級(jí)異常");
} else if (e instanceof ParamFlowException) {
data = new Result(-3, "參數(shù)限流異常");
} else if (e instanceof AuthorityException) {
data = new Result(-4, "授權(quán)異常");
} else if (e instanceof SystemBlockException) {
data = new Result(-5, "系統(tǒng)負(fù)載異常");
}
response.getWriter().write(JSON.toJSONString(data));
}
}
// 統(tǒng)一返回體
class Result {
private int status;
private String msg;
private Object data;
// 省略getter/setter/構(gòu)造器
}5.3 Sentinel 整合 Feign
實(shí)現(xiàn) Feign 遠(yuǎn)程調(diào)用的熔斷降級(jí),避免下游服務(wù)異常影響上游。
5.3.1 實(shí)現(xiàn) FallbackFactory
@Component
public class UserFeignFallback implements FallbackFactory<UserFeign> {
@Override
public UserFeign create(Throwable t) {
return new UserFeign() {
@Override
public User getUserById(Integer id) {
return new User(id, "Feign調(diào)用失?。?+t, 0);
}
};
}
}5.3.2 配置 Feign 接口
@FeignClient(value = "sentinel-provider", fallbackFactory = UserFeignFallback.class)
public interface UserFeign {
@RequestMapping(value = "/provider/getUserById/{id}")
User getUserById(@PathVariable Integer id);
}
六、總結(jié)
Sentinel 憑借輕量、易用、靈活的特性,成為 SpringCloud 微服務(wù)架構(gòu)中服務(wù)保護(hù)的首選方案。核心要點(diǎn)總結(jié):
- 資源定義:通過硬編碼 / 注解 / 自動(dòng)適配(SpringMVC/Feign)定義受保護(hù)資源;
- 規(guī)則配置:控制臺(tái) / 代碼配置流量控制、熔斷降級(jí)等規(guī)則,按需選擇粒度;
- 兜底邏輯:通過 blockHandler / 全局異常 / FallbackFactory 處理限流 / 熔斷場(chǎng)景;
- 核心價(jià)值:從流量入口到服務(wù)調(diào)用全鏈路保護(hù),防止雪崩效應(yīng),保障微服務(wù)高可用。
建議結(jié)合 JMeter 壓測(cè)工具驗(yàn)證各類規(guī)則效果,加深對(duì) Sentinel 流量控制、熔斷降級(jí)的理解,根據(jù)業(yè)務(wù)場(chǎng)景靈活配置規(guī)則,平衡系統(tǒng)穩(wěn)定性和可用性。
到此這篇關(guān)于SpringCloud Alibaba Sentinel 從入門到精通的文章就介紹到這了,更多相關(guān)SpringCloud Alibaba Sentinel 使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中Arrays.asList()方法詳解及實(shí)例
這篇文章主要介紹了Java中Arrays.asList()方法將數(shù)組作為列表時(shí)的一些差異的相關(guān)資料,需要的朋友可以參考下2017-06-06
Java中JUC包(java.util.concurrent)下的常用子類
相信大家已經(jīng)對(duì)并發(fā)機(jī)制中出現(xiàn)的很多的常見知識(shí)點(diǎn)進(jìn)行了總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java中JUC包(java.util.concurrent)下的常用子類的相關(guān)資料,文中通過圖文以及示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12
Java報(bào)錯(cuò)Non-terminating?decimal?expansion解決分析
這篇文章主要為大家介紹了Java報(bào)錯(cuò)Non-terminating?decimal?expansion解決方案及原理分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
修改idea運(yùn)行內(nèi)存大小的方法總結(jié)
在開發(fā)過程中,總會(huì)遇到idea運(yùn)行內(nèi)存不足,所以本文小編給大家介紹了修改idea運(yùn)行內(nèi)存大小的兩種方法,文中通過圖文給大家講解的非常詳細(xì),需要的朋友可以參考下2023-12-12

