
👋 大家好,欢迎来到我的技术博客!
💻 作为一名热爱 Java 与软件开发的程序员,我始终相信:清晰的逻辑 + 持续的积累 = 稳健的成长 。
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Sentinel 这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!
文章目录
- [Sentinel - 在 Dubbo 微服务中使用:Alibaba 生态无缝集成 🚀](#Sentinel - 在 Dubbo 微服务中使用:Alibaba 生态无缝集成 🚀)
-
- [一、Sentinel 概述:微服务的流量守护神 🛡️](#一、Sentinel 概述:微服务的流量守护神 🛡️)
-
- [1.1 什么是 Sentinel?](#1.1 什么是 Sentinel?)
- [1.2 Sentinel 的优势](#1.2 Sentinel 的优势)
- [二、Dubbo 微服务架构简介:服务调用的基石 🏗️](#二、Dubbo 微服务架构简介:服务调用的基石 🏗️)
- [三、Dubbo + Sentinel 集成方案详解 🔧](#三、Dubbo + Sentinel 集成方案详解 🔧)
-
- [3.1 核心思想](#3.1 核心思想)
- [3.2 必需依赖](#3.2 必需依赖)
- [3.3 配置方式](#3.3 配置方式)
-
- [3.3.1 Maven 依赖配置](#3.3.1 Maven 依赖配置)
- [3.3.2 应用配置文件 (application.yml)](#3.3.2 应用配置文件 (application.yml))
- [3.3.3 启动类注解](#3.3.3 启动类注解)
- [3.4 服务提供者 (Provider) 集成](#3.4 服务提供者 (Provider) 集成)
-
- [3.4.1 创建服务接口](#3.4.1 创建服务接口)
- [3.4.2 实现服务接口](#3.4.2 实现服务接口)
- [3.5 服务消费者 (Consumer) 集成](#3.5 服务消费者 (Consumer) 集成)
-
- [3.5.1 调用服务接口](#3.5.1 调用服务接口)
- [四、Sentinel 规则配置与管理 🛠️](#四、Sentinel 规则配置与管理 🛠️)
-
- [4.1 流量控制规则 (Flow Rule)](#4.1 流量控制规则 (Flow Rule))
-
- [4.1.1 配置项说明](#4.1.1 配置项说明)
- [4.1.2 示例:设置 `sayHello` 接口 QPS 限制为 1](#4.1.2 示例:设置
sayHello接口 QPS 限制为 1) - [4.1.3 代码演示](#4.1.3 代码演示)
- [4.2 熔断降级规则 (Degrade Rule)](#4.2 熔断降级规则 (Degrade Rule))
-
- [4.2.1 配置项说明](#4.2.1 配置项说明)
- [4.2.2 示例:设置 `calculate` 接口异常比例熔断](#4.2.2 示例:设置
calculate接口异常比例熔断) - [4.2.3 代码演示](#4.2.3 代码演示)
- [4.3 系统保护规则 (System Rule)](#4.3 系统保护规则 (System Rule))
-
- [4.3.1 配置项说明](#4.3.1 配置项说明)
- [4.3.2 示例:设置系统负载保护](#4.3.2 示例:设置系统负载保护)
- [4.4 热点参数限流规则 (Hotspot Param Rule)](#4.4 热点参数限流规则 (Hotspot Param Rule))
-
- [4.4.1 配置项说明](#4.4.1 配置项说明)
- [4.4.2 示例:对 `sayHello` 方法的 `name` 参数进行限流](#4.4.2 示例:对
sayHello方法的name参数进行限流)
- [五、Sentinel Dashboard 使用指南 📊](#五、Sentinel Dashboard 使用指南 📊)
-
- [5.1 启动 Dashboard](#5.1 启动 Dashboard)
- [5.2 功能概览](#5.2 功能概览)
- [5.3 实时监控面板](#5.3 实时监控面板)
- [六、实战演练:构建一个完整的 Dubbo + Sentinel 应用 🧪](#六、实战演练:构建一个完整的 Dubbo + Sentinel 应用 🧪)
-
- [6.1 项目结构](#6.1 项目结构)
- [6.2 依赖管理 (pom.xml)](#6.2 依赖管理 (pom.xml))
- [6.3 API 模块](#6.3 API 模块)
-
- [6.3.1 GreetingService.java](#6.3.1 GreetingService.java)
- [6.4 Provider 模块](#6.4 Provider 模块)
-
- [6.4.1 pom.xml](#6.4.1 pom.xml)
- [6.4.2 GreetingServiceImpl.java](#6.4.2 GreetingServiceImpl.java)
- [6.4.3 DubboProviderApplication.java](#6.4.3 DubboProviderApplication.java)
- [6.4.4 application.yml](#6.4.4 application.yml)
- [6.5 Consumer 模块](#6.5 Consumer 模块)
-
- [6.5.1 pom.xml](#6.5.1 pom.xml)
- [6.5.2 ConsumerController.java](#6.5.2 ConsumerController.java)
- [6.5.3 DubboConsumerApplication.java](#6.5.3 DubboConsumerApplication.java)
- [6.5.4 application.yml](#6.5.4 application.yml)
- [6.6 启动顺序与测试](#6.6 启动顺序与测试)
- [七、高级特性与最佳实践 🌟](#七、高级特性与最佳实践 🌟)
-
- [7.1 自定义异常处理](#7.1 自定义异常处理)
- [7.2 集群流控 (Cluster Flow Control)](#7.2 集群流控 (Cluster Flow Control))
- [7.3 规则持久化](#7.3 规则持久化)
- [7.4 性能优化](#7.4 性能优化)
- [7.5 监控与告警](#7.5 监控与告警)
- [八、常见问题与解决方案 ❓](#八、常见问题与解决方案 ❓)
-
- [8.1 无法连接到 Sentinel Dashboard](#8.1 无法连接到 Sentinel Dashboard)
- [8.2 规则未生效](#8.2 规则未生效)
- [8.3 熔断后无法恢复](#8.3 熔断后无法恢复)
- [九、总结与展望 📝](#九、总结与展望 📝)
- [附录:Mermaid 图表](#附录:Mermaid 图表)
-
- 服务调用流程图
- [Sentinel 规则交互图](#Sentinel 规则交互图)
Sentinel - 在 Dubbo 微服务中使用:Alibaba 生态无缝集成 🚀
在现代微服务架构中,服务间的调用变得日益复杂,服务的高可用性和稳定性成为保障系统整体健康的关键。随着服务数量的增长和调用链路的延伸,单个服务的故障可能引发雪崩效应,导致整个系统瘫痪。因此,如何有效地进行流量控制、熔断降级、系统负载保护以及实时监控,成为了构建健壮微服务系统的核心挑战。
阿里巴巴开源的 Sentinel,作为一款面向分布式服务架构的流量治理组件,正是为了解决这些问题而诞生。它提供了丰富的流量控制、熔断降级、系统负载保护等能力,并且与 Spring Cloud、Dubbo 等主流微服务框架实现了无缝集成。本文将深入探讨如何在基于 Dubbo 构建的微服务系统中,利用 Sentinel 实现服务治理,确保系统的稳定运行。
一、Sentinel 概述:微服务的流量守护神 🛡️
1.1 什么是 Sentinel?
Sentinel 是阿里巴巴开源的一款面向分布式服务架构的流量治理组件,其核心理念是"流量控制、熔断降级、系统负载保护"。它能够帮助开发者在复杂的微服务环境中,轻松地应对各种流量场景,保障服务的稳定性和可靠性。
💡 核心功能:
- 流量控制 (Flow Control):根据设定的规则,对进入服务的流量进行限制,防止因瞬时流量过大导致服务过载或崩溃。
- 熔断降级 (Circuit Breaking & Degradation):当服务出现异常或响应缓慢时,自动触发熔断机制,快速失败并返回降级结果,避免故障扩散。
- 系统负载保护 (System Protection):通过监控系统负载(如 CPU 使用率、系统平均负载),在系统压力过大时拒绝新请求,保护系统不被压垮。
- 实时监控 (Monitoring):提供实时的监控面板,方便运维人员查看服务状态、流量指标和规则配置。
1.2 Sentinel 的优势
- 易于集成:支持 Spring Boot、Dubbo、Spring Cloud 等主流框架,集成成本低。
- 丰富的规则管理:支持多种规则类型,包括流量控制规则、熔断规则、系统规则等,并可通过控制台动态配置。
- 实时监控:提供实时监控面板,直观展示服务状态和流量数据。
- 性能优异:采用高性能的并发处理机制,对业务代码的侵入性极小。
- 社区活跃:拥有庞大的用户群体和活跃的社区支持。
二、Dubbo 微服务架构简介:服务调用的基石 🏗️
在深入探讨 Sentinel 与 Dubbo 的集成之前,我们先简要回顾一下 Dubbo 的核心概念,以便更好地理解后续的整合过程。
Dubbo 是一个高性能的 Java RPC 框架,它主要由以下几个核心组件构成:
- Provider (服务提供者):暴露服务的节点,负责实现具体的服务逻辑。
- Consumer (服务消费者):调用远程服务的节点。
- Registry (注册中心):用于服务的注册与发现,例如 Zookeeper、Nacos 等。
- Monitor (监控中心):收集服务调用次数、耗时等统计信息。
Dubbo 通过注册中心实现了服务的自动发现和负载均衡,使得服务之间的调用变得更加简单和透明。然而,在服务调用过程中,如果没有有效的流量治理手段,很容易出现服务雪崩等问题。这正是 Sentinel 发挥作用的地方。
三、Dubbo + Sentinel 集成方案详解 🔧
3.1 核心思想
在 Dubbo 中集成 Sentinel 的核心思想是:在 Dubbo 的服务调用链路中,注入 Sentinel 的流量控制和熔断降级逻辑。这意味着,当服务提供者或消费者发起或接收 Dubbo 调用时,Sentinel 会根据预设的规则进行拦截和处理。
3.2 必需依赖
要实现 Dubbo 与 Sentinel 的集成,需要引入以下关键依赖:
- Dubbo: 用于构建微服务。
- Dubbo-Registry-Nacos / Zookeeper: 用于服务注册与发现(这里以 Nacos 为例)。
- Sentinel-Dubbo-Adapter: 这是 Dubbo 与 Sentinel 集成的核心适配器,它提供了 Dubbo 服务调用的接入点,使得 Sentinel 能够感知 Dubbo 的调用。
- Sentinel-Spring-Boot-Starter : 或者
sentinel-core和sentinel-transport-simple-http等核心包,用于启动 Sentinel 控制台和核心功能。 - Sentinel-Dashboard: Sentinel 控制台,用于可视化配置规则和监控数据。
3.3 配置方式
3.3.1 Maven 依赖配置
首先,我们需要在项目 pom.xml 文件中添加必要的依赖项。下面是一个示例配置:
xml
<dependencies>
<!-- Dubbo 核心 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.2.10</version> <!-- 使用较新版本 -->
</dependency>
<!-- Dubbo 注册中心 (Nacos) -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>3.2.10</version>
</dependency>
<!-- Sentinel Dubbo 适配器 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>1.8.6</version> <!-- 请确认使用最新版本 -->
</dependency>
<!-- Sentinel Spring Boot Starter (包含核心和控制台客户端) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2022.0.0.0-RC2</version> <!-- 请确认使用兼容的版本 -->
</dependency>
<!-- 如果使用 Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 其他必要依赖... -->
</dependencies>
📝 注意: 版本号应根据你的实际环境选择,建议参考官方文档或 Maven 中央仓库获取最新版本。例如,Sentinel 官方 GitHub 和 Dubbo 官方文档。
3.3.2 应用配置文件 (application.yml)
接下来,在 application.yml 中进行基础配置:
yaml
server:
port: 8080 # 服务端口
dubbo:
application:
name: dubbo-provider # 应用名称
registry:
address: nacos://localhost:8848 # Nacos 地址
protocol:
name: dubbo
port: 20880
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 # Sentinel 控制台地址
port: 8080 # 客户端向控制台发送心跳的端口 (可选)
eager: true # 启动时立即初始化 Sentinel
# 可选:配置规则持久化相关
# config:
# rule-type: file # 或者其他持久化方式
3.3.3 启动类注解
确保你的 Spring Boot 启动类上添加了 @EnableDubbo 和 @EnableSentinel 注解(如果使用了 Spring Cloud Alibaba):
java
// 示例:服务提供者启动类
@SpringBootApplication
@EnableDubbo // 启用 Dubbo
public class DubboProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DubboProviderApplication.class, args);
}
}
⚠️ 重要:
sentinel-dubbo-adapter通常在 Dubbo 3.x 版本中需要手动配置,或者通过 Spring Boot 的自动装配来加载。确保你的 Dubbo 版本与 Sentinel 的适配器版本兼容。
3.4 服务提供者 (Provider) 集成
服务提供者是 Dubbo 中提供具体业务逻辑的组件。为了让 Sentinel 对其调用进行控制,需要在服务接口实现类上添加 @SentinelResource 注解。
3.4.1 创建服务接口
java
// api/src/main/java/com/example/dubbo/api/GreetingService.java
package com.example.dubbo.api;
public interface GreetingService {
String sayHello(String name);
int calculate(int a, int b); // 假设这个方法可能会出错
}
3.4.2 实现服务接口
java
// provider/src/main/java/com/example/dubbo/provider/GreetingServiceImpl.java
package com.example.dubbo.provider;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.dubbo.api.GreetingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service(version = "1.0.0") // Dubbo 注解,暴露服务
public class GreetingServiceImpl implements GreetingService {
private static final Logger logger = LoggerFactory.getLogger(GreetingServiceImpl.class);
@Override
@SentinelResource(value = "sayHello", blockHandler = "handleBlockException", fallback = "fallbackSayHello")
public String sayHello(String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Name cannot be empty");
}
logger.info("Received request for hello: {}", name);
return "Hello, " + name + "!";
}
@Override
@SentinelResource(value = "calculate", blockHandler = "handleCalculateBlockException", fallback = "fallbackCalculate")
public int calculate(int a, int b) {
// 模拟计算耗时
try {
Thread.sleep(100); // 模拟慢操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 模拟异常情况
if (a < 0 || b < 0) {
throw new RuntimeException("Negative numbers not allowed in calculation");
}
int result = a + b;
logger.info("Calculation result: {} + {} = {}", a, b, result);
return result;
}
// BlockHandler 方法:处理流控、降级规则触发的情况
public String handleBlockException(String name, BlockException ex) {
logger.warn("Flow control or circuit breaking triggered for sayHello, name: {}, exception: {}", name, ex.getClass().getSimpleName());
return "Blocked: Service is too busy, please try again later.";
}
// Fallback 方法:处理服务异常或降级的情况
public String fallbackSayHello(String name, Throwable ex) {
logger.error("Fallback triggered for sayHello due to error: ", ex);
return "Fallback: Service unavailable, sorry!";
}
// BlockHandler for calculate
public int handleCalculateBlockException(int a, int b, BlockException ex) {
logger.warn("Flow control or circuit breaking triggered for calculate, params: ({}, {}), exception: {}", a, b, ex.getClass().getSimpleName());
return -1; // 返回默认值
}
// Fallback for calculate
public int fallbackCalculate(int a, int b, Throwable ex) {
logger.error("Fallback triggered for calculate due to error: ", ex);
return -1; // 返回默认值
}
}
🧠 关键点解析:
@Service(version = "1.0.0"): 这是 Dubbo 的注解,用于将该类注册为服务提供者。@SentinelResource(value = "..."): 这是 Sentinel 的核心注解,指定资源名(通常是方法名)。blockHandler属性指向流控/熔断后的处理方法;fallback属性指向异常降级后的处理方法。handleBlockException,fallbackSayHello,handleCalculateBlockException,fallbackCalculate: 这些是具体的回调方法,用于定义在发生流控、降级或异常时的处理逻辑。
3.5 服务消费者 (Consumer) 集成
服务消费者通过调用 Dubbo 提供的服务来完成业务逻辑。为了使 Sentinel 能够对消费者的调用进行控制,同样需要在调用方的方法上使用 @SentinelResource 注解。
3.5.1 调用服务接口
java
// consumer/src/main/java/com/example/dubbo/consumer/ConsumerController.java
package com.example.dubbo.consumer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.dubbo.api.GreetingService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Reference(version = "1.0.0") // Dubbo 注解,引用远程服务
private GreetingService greetingService;
@GetMapping("/hello")
@SentinelResource(value = "consumer-hello", blockHandler = "handleHelloBlock", fallback = "fallbackHello")
public String hello(@RequestParam String name) {
// 调用远程服务
return greetingService.sayHello(name);
}
@GetMapping("/calc")
@SentinelResource(value = "consumer-calc", blockHandler = "handleCalcBlock", fallback = "fallbackCalc")
public int calculate(@RequestParam int a, @RequestParam int b) {
return greetingService.calculate(a, b);
}
// BlockHandler 方法
public String handleHelloBlock(String name, BlockException ex) {
return "Blocked: Consumer service is overloaded or under maintenance.";
}
public String fallbackHello(String name, Throwable ex) {
return "Fallback: Consumer failed to get response from provider.";
}
public int handleCalcBlock(int a, int b, BlockException ex) {
return -1; // 默认值
}
public int fallbackCalc(int a, int b, Throwable ex) {
return -1; // 默认值
}
}
🧠 关键点解析:
@Reference(version = "1.0.0"): 这是 Dubbo 的注解,用于注入远程服务的代理对象。@SentinelResource(value = "consumer-hello"): 对消费者调用进行资源标识。handleHelloBlock,fallbackHello,handleCalcBlock,fallbackCalc: 对应消费者调用时的流控、降级处理逻辑。
四、Sentinel 规则配置与管理 🛠️
Sentinel 的强大之处在于其灵活的规则配置。这些规则可以动态地应用于不同的资源,实现精细化的流量控制。
4.1 流量控制规则 (Flow Rule)
流量控制规则用于限制特定资源的访问频率,防止瞬时流量过高导致服务不可用。
4.1.1 配置项说明
| 属性 | 说明 |
|---|---|
resource |
资源名,即 @SentinelResource 注解中的 value 值。 |
limitApp |
限流来源应用,用于区分不同来源的流量。 |
grade |
限流阈值类型,QPS(每秒请求数)或 Thread(线程数)。 |
count |
限流阈值。 |
strategy |
调用关系限流策略,0 (直接)、1 (关联)、2 (链路)。 |
controlBehavior |
流控效果,0 (快速失败)、1 (Warm Up)、2 (匀速排队)。 |
4.1.2 示例:设置 sayHello 接口 QPS 限制为 1
在 Sentinel Dashboard 上配置规则:
- 登录 Sentinel Dashboard (通常在
http://localhost:8080)。 - 选择对应的
App Name(例如dubbo-provider)。 - 点击左侧菜单栏的
流控规则。 - 点击
新增流控规则。 - 填写参数:
资源名:sayHello限流阈值:1(表示每秒最多允许 1 个请求)限流模式:QPS(每秒请求数)流控效果:快速失败(默认)流控策略:直接(默认)
- 点击
保存。
4.1.3 代码演示
当 sayHello 接口被频繁调用(超过 1 QPS)时,会触发流控规则,handleBlockException 方法会被调用。
4.2 熔断降级规则 (Degrade Rule)
熔断降级规则用于在服务出现不稳定(如超时、异常比例过高)时,自动切断对该服务的调用,避免故障扩散。
4.2.1 配置项说明
| 属性 | 说明 |
|---|---|
resource |
资源名。 |
grade |
熔断策略,0 (慢调用比例)、1 (异常比例)、2 (异常数)。 |
count |
阈值。 |
timeWindow |
熔断时长,单位为秒。 |
minRequestAmount |
最小请求数。 |
4.2.2 示例:设置 calculate 接口异常比例熔断
配置规则:
- 选择
熔断降级规则。 - 新增规则。
- 参数:
资源名:calculate熔断策略:异常比例(例如1表示 1% 的请求异常就会触发熔断)异常比例阈值:0.5(50%)熔断时长:5秒最小请求数:10(至少有 10 个请求才会考虑熔断)
- 保存。
4.2.3 代码演示
如果 calculate 接口在 5 秒内,有 50% 的调用出现了异常(例如抛出了 RuntimeException),则会触发熔断。此时,所有对该接口的调用都会直接进入 fallbackCalculate 方法,返回默认值。
4.3 系统保护规则 (System Rule)
系统保护规则用于保护整个系统,防止因某个服务负载过高而导致整个系统崩溃。
4.3.1 配置项说明
| 属性 | 说明 |
|---|---|
mode |
系统保护模式,0 (Load)、1 (CPU)、2 (QPS)、3 (RT)。 |
threshold |
阈值。 |
4.3.2 示例:设置系统负载保护
配置规则:
- 选择
系统规则。 - 新增规则。
- 参数:
模式:Load(系统负载)阈值:3(系统平均负载超过 3 时触发保护)
- 保存。
4.4 热点参数限流规则 (Hotspot Param Rule)
热点参数限流规则用于对特定参数的值进行限流,常用于对热门参数(如商品 ID)进行流量控制。
⚠️ 注意:此规则需要配合
@SentinelResource注解中的paramIndex属性使用。
4.4.1 配置项说明
| 属性 | 说明 |
|---|---|
resource |
资源名。 |
paramIndex |
参数索引,表示哪个参数参与限流。 |
paramType |
参数类型。 |
limitApp |
限流来源。 |
count |
限流阈值。 |
grade |
限流模式,QPS 或 Thread。 |
controlBehavior |
流控效果。 |
maxQueueingTimeMs |
匀速排队时的最大等待时间。 |
4.4.2 示例:对 sayHello 方法的 name 参数进行限流
修改 GreetingServiceImpl:
java
// ... (其他代码不变)
@Override
@SentinelResource(value = "sayHello", blockHandler = "handleBlockException", fallback = "fallbackSayHello", paramIndex = 0) // index 0 代表第一个参数 name
public String sayHello(String name) {
// ... 业务逻辑
}
// ... (其他代码不变)
然后在 Dashboard 上配置规则:
- 选择
热点参数规则。 - 新增规则。
- 参数:
资源名:sayHello参数索引:0(对应name参数)参数类型:String限流阈值:1限流模式:QPS流控效果:快速失败
- 保存。
🧠 注意:
paramIndex从 0 开始计数。例如,对于calculate(int a, int b)方法,a对应paramIndex = 0,b对应paramIndex = 1。
五、Sentinel Dashboard 使用指南 📊
Sentinel Dashboard 是 Sentinel 的可视化管理界面,它提供了强大的规则管理和实时监控功能。
5.1 启动 Dashboard
-
下载 Sentinel Dashboard 的 jar 包:Sentinel Dashboard GitHub Releases。
-
运行命令:
bashjava -jar sentinel-dashboard.jar --server.port=8080 -
访问
http://localhost:8080,默认用户名密码为sentinel/sentinel。
5.2 功能概览
- 应用列表 (App List): 显示所有已接入 Sentinel 的应用。
- 流控规则 (Flow Rules): 查看和配置流控规则。
- 熔断降级规则 (Degrade Rules): 查看和配置熔断降级规则。
- 系统规则 (System Rules): 查看和配置系统保护规则。
- 热点参数规则 (Hotspot Param Rules): 查看和配置热点参数规则。
- 授权规则 (Authority Rules): 配置访问权限。
- 集群流控 (Cluster Flow Rules): 配置集群模式下的流控。
- 实时监控 (Metrics): 实时查看各应用的监控指标,如 QPS、响应时间、错误率等。
5.3 实时监控面板
在 Dashboard 的 实时监控 页面,你可以看到:
- 应用概览: 展示所有应用的实时状态。
- 资源详情 : 点击任意资源名,可以看到该资源的详细监控信息,包括:
- QPS (Queries Per Second): 每秒查询数。
- 平均响应时间 (Average RT): 平均响应时间。
- 错误率 (Error Rate): 错误请求的比例。
- 通过数 (Pass): 成功通过的请求数。
- 拒绝数 (Block): 被拒绝的请求数。
- 慢调用数 (Slow): 被标记为慢调用的请求数。
六、实战演练:构建一个完整的 Dubbo + Sentinel 应用 🧪
让我们通过一个完整的示例,来实践上述的所有知识点。
6.1 项目结构
假设我们有一个名为 dubbo-sentinel-demo 的多模块 Maven 项目,结构如下:
dubbo-sentinel-demo/
├── api/ # API 接口模块
│ └── src/main/java/com/example/dubbo/api/
│ └── GreetingService.java
├── provider/ # 服务提供者模块
│ └── src/main/java/com/example/dubbo/provider/
│ ├── GreetingServiceImpl.java
│ └── DubboProviderApplication.java
├── consumer/ # 服务消费者模块
│ └── src/main/java/com/example/dubbo/consumer/
│ ├── ConsumerController.java
│ └── DubboConsumerApplication.java
└── pom.xml # 父 POM
6.2 依赖管理 (pom.xml)
xml
<!-- 父 POM -->
<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.example</groupId>
<artifactId>dubbo-sentinel-demo</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>api</module>
<module>provider</module>
<module>consumer</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<spring.boot.version>3.1.0</spring.boot.version>
<dubbo.version>3.2.10</dubbo.version>
<sentinel.version>1.8.6</sentinel.version>
<nacos.version>2.2.0</nacos.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2022.0.0.0-RC2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
6.3 API 模块
6.3.1 GreetingService.java
java
// api/src/main/java/com/example/dubbo/api/GreetingService.java
package com.example.dubbo.api;
public interface GreetingService {
String sayHello(String name);
int calculate(int a, int b);
}
6.4 Provider 模块
6.4.1 pom.xml
xml
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
6.4.2 GreetingServiceImpl.java
java
// provider/src/main/java/com/example/dubbo/provider/GreetingServiceImpl.java
package com.example.dubbo.provider;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.dubbo.api.GreetingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service(version = "1.0.0")
public class GreetingServiceImpl implements GreetingService {
private static final Logger logger = LoggerFactory.getLogger(GreetingServiceImpl.class);
@Override
@SentinelResource(value = "sayHello", blockHandler = "handleBlockException", fallback = "fallbackSayHello")
public String sayHello(String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Name cannot be empty");
}
logger.info("Received request for hello: {}", name);
return "Hello, " + name + "!";
}
@Override
@SentinelResource(value = "calculate", blockHandler = "handleCalculateBlockException", fallback = "fallbackCalculate")
public int calculate(int a, int b) {
// 模拟计算耗时
try {
Thread.sleep(100); // 模拟慢操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 模拟异常情况
if (a < 0 || b < 0) {
throw new RuntimeException("Negative numbers not allowed in calculation");
}
int result = a + b;
logger.info("Calculation result: {} + {} = {}", a, b, result);
return result;
}
public String handleBlockException(String name, BlockException ex) {
logger.warn("Flow control or circuit breaking triggered for sayHello, name: {}, exception: {}", name, ex.getClass().getSimpleName());
return "Blocked: Service is too busy, please try again later.";
}
public String fallbackSayHello(String name, Throwable ex) {
logger.error("Fallback triggered for sayHello due to error: ", ex);
return "Fallback: Service unavailable, sorry!";
}
public int handleCalculateBlockException(int a, int b, BlockException ex) {
logger.warn("Flow control or circuit breaking triggered for calculate, params: ({}, {}), exception: {}", a, b, ex.getClass().getSimpleName());
return -1;
}
public int fallbackCalculate(int a, int b, Throwable ex) {
logger.error("Fallback triggered for calculate due to error: ", ex);
return -1;
}
}
6.4.3 DubboProviderApplication.java
java
// provider/src/main/java/com/example/dubbo/provider/DubboProviderApplication.java
package com.example.dubbo.provider;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
public class DubboProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DubboProviderApplication.class, args);
}
}
6.4.4 application.yml
yaml
server:
port: 8081
dubbo:
application:
name: dubbo-provider
registry:
address: nacos://localhost:8848
protocol:
name: dubbo
port: 20880
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
port: 8080
eager: true
6.5 Consumer 模块
6.5.1 pom.xml
xml
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
6.5.2 ConsumerController.java
java
// consumer/src/main/java/com/example/dubbo/consumer/ConsumerController.java
package com.example.dubbo.consumer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.dubbo.api.GreetingService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Reference(version = "1.0.0")
private GreetingService greetingService;
@GetMapping("/hello")
@SentinelResource(value = "consumer-hello", blockHandler = "handleHelloBlock", fallback = "fallbackHello")
public String hello(@RequestParam String name) {
return greetingService.sayHello(name);
}
@GetMapping("/calc")
@SentinelResource(value = "consumer-calc", blockHandler = "handleCalcBlock", fallback = "fallbackCalc")
public int calculate(@RequestParam int a, @RequestParam int b) {
return greetingService.calculate(a, b);
}
public String handleHelloBlock(String name, BlockException ex) {
return "Blocked: Consumer service is overloaded or under maintenance.";
}
public String fallbackHello(String name, Throwable ex) {
return "Fallback: Consumer failed to get response from provider.";
}
public int handleCalcBlock(int a, int b, BlockException ex) {
return -1;
}
public int fallbackCalc(int a, int b, Throwable ex) {
return -1;
}
}
6.5.3 DubboConsumerApplication.java
java
// consumer/src/main/java/com/example/dubbo/consumer/DubboConsumerApplication.java
package com.example.dubbo.consumer;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
public class DubboConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DubboConsumerApplication.class, args);
}
}
6.5.4 application.yml
yaml
server:
port: 8082
dubbo:
application:
name: dubbo-consumer
registry:
address: nacos://localhost:8848
protocol:
name: dubbo
port: 20880
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
port: 8080
eager: true
6.6 启动顺序与测试
- 启动 Nacos : 确保 Nacos 服务器正在运行在
localhost:8848。 - 启动 Sentinel Dashboard : 运行
java -jar sentinel-dashboard.jar --server.port=8080。 - 启动 Provider : 运行
DubboProviderApplication。 - 启动 Consumer : 运行
DubboConsumerApplication。 - 访问接口 :
http://localhost:8082/hello?name=Alice- 调用消费者接口。http://localhost:8082/calc?a=1&b=2- 调用消费者接口。
- 查看 Dashboard : 登录
http://localhost:8080,观察监控面板和规则配置。
七、高级特性与最佳实践 🌟
7.1 自定义异常处理
除了使用 @SentinelResource 的 fallback 和 blockHandler 外,还可以结合 @ExceptionHandler 或全局异常处理器进行更细粒度的控制。
7.2 集群流控 (Cluster Flow Control)
在生产环境中,单机限流往往不足以应对大规模流量。Sentinel 支持集群模式,可以将多个实例的流量汇聚到一个中心节点进行统一管理。
7.3 规则持久化
在生产环境中,规则变更需要持久化存储,避免重启后丢失。可以通过配置 sentinel-config 或者使用 Nacos 等配置中心来实现规则的持久化。
7.4 性能优化
- 合理设置规则: 避免过于复杂的规则,影响性能。
- 选择合适的资源名: 资源名越具体,控制越精细,但也会增加开销。
- 使用缓存: 对于频繁调用且结果稳定的接口,可以考虑在应用层进行缓存。
7.5 监控与告警
结合 Prometheus 和 Grafana 等工具,可以对 Sentinel 的监控数据进行更深入的分析和可视化,并设置告警规则。
八、常见问题与解决方案 ❓
8.1 无法连接到 Sentinel Dashboard
- 原因: 网络不通、Dashboard 地址配置错误。
- 解决 : 检查网络连接,确认
spring.cloud.sentinel.transport.dashboard配置正确。
8.2 规则未生效
- 原因: 规则未正确配置、资源名不匹配、未启用 Sentinel。
- 解决 : 检查 Dashboard 规则配置,确认资源名与
@SentinelResource注解一致,检查是否正确启用了 Sentinel。
8.3 熔断后无法恢复
- 原因: 熔断时间未到。
- 解决: 等待熔断时间结束,或手动重置熔断状态。
九、总结与展望 📝
通过本文的详细介绍,我们已经掌握了如何在 Dubbo 微服务架构中集成 Sentinel,利用其强大的流量控制、熔断降级、系统保护等功能,保障服务的高可用性与稳定性。Sentinel 作为阿里巴巴生态中的重要组件,其与 Dubbo 的无缝集成,为构建现代化的微服务系统提供了坚实的基础。
未来,随着微服务架构的不断发展,流量治理的需求将更加复杂和多样化。Sentinel 也在持续演进,增加了更多的特性和优化。开发者应密切关注其更新,结合自身业务场景,不断探索和实践更高效的流量治理方案。
希望本文能为你在实际项目中应用 Sentinel 提供有价值的参考。记住,良好的服务治理是微服务成功的关键!🚀
附录:Mermaid 图表
服务调用流程图
渲染错误: Mermaid 渲染失败: Parse error on line 3: ...GreetingService
(Dubbo Interface)] -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
Sentinel 规则交互图
Dubbo Integration
Sentinel Core
Rules
Context
Flow Control
Circuit Break
System Protection
Hotspot Param
Dubbo Call
Inject Context
Rule Manager
Slot Chain
Context
Flow Slot
Degrade Slot
System Slot
Hotspot Slot
Service Provider
Service Consumer
Sentinel Dubbo Adapter
📘 参考资料:
🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞 、📌 收藏 、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨