Spring Cloud Alibaba:兼容矩阵、Nacos 接入与 Sentinel 规则
选择 Spring Cloud Alibaba 时,首先需要确定应用要接入哪些服务:用 Nacos 查找实例、读取配置,用 Sentinel 保护调用,或通过 RocketMQ 传递消息。选定组件以后,再把 Spring Boot、Spring Cloud、Alibaba BOM 和服务端版本放到同一张表里核对。
这些依赖分别控制不同对象。应用编译通过以后,还需要验证服务端连接、鉴权和运行中的配置变化。
版本组合决定可以安装哪些组件
BOM、Starter、SDK 和服务端各自装在哪里
Spring Cloud Alibaba(SCA)把相关中间件接入 Spring Cloud 编程模型。BOM 管理一组 Maven 依赖版本;Starter 提供自动配置及依赖入口;SDK 在应用进程里连接服务端。Nacos Server、RocketMQ Broker、Seata Server 等仍是独立部署的进程。SCA 项目概述介绍了这一集成定位。
应用的 Maven 工程
├─ Spring Boot Parent 构建插件和基础依赖管理
├─ Spring Cloud BOM Cloud 子项目版本
├─ Spring Cloud Alibaba BOM Alibaba 组件适配版本
└─ 选用的 Starter
├─ Nacos SDK 配置订阅、实例注册与查询
└─ Sentinel Core 当前进程中的资源统计与规则检查
另行部署
├─ Nacos Server 配置存储、连接管理、服务实例目录
├─ Nacos Console 管理入口,3.x 有独立端口
└─ 其他实际选用的服务端 Broker、事务协调器、调度服务等只引入 BOM 不会启动 Nacos;安装 Nacos 也不会自动给 Controller 限流。Sentinel 的资源保护代码在应用内执行,Dashboard 主要承担管理和观察工作,请求不必先穿过 Dashboard。
按官方矩阵固定实验
下面是 SCA 2025.x 版本矩阵列出的精确组合。实验固定其中一行,便于排除混装带来的差异。
| 对象 | 固定版本或条件 |
|---|---|
| Java 源码目标 | Java 17;构建和测试可分别使用 JDK 17、25 |
| Maven | 3.9.12 |
| Spring Boot | 4.0.0 |
| Spring Cloud | 2025.1.0 |
| Spring Cloud Alibaba | 2025.1.0.0 |
| Nacos Client / Server | 3.1.1 / 3.1.1 |
| Sentinel | 1.8.9 |
这是旧补丁的可复现实验基线,不能据此选择生产补丁。生产升级还要核对维护状态、安全公告与服务端升级说明。SCA 2025.1.x 的矩阵声明适配 Boot 4.0.x;前几篇使用的 Boot 4.1.1 不应直接移入这份工程。
POM 使用 Boot 4.0.0 Parent,再导入 Alibaba 与 Cloud BOM。依赖处仅声明所需 Starter,不逐个覆盖它们带入的 Nacos、Sentinel 或 Spring 类库:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2025.1.0.0</version>
<type>pom</type><scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2025.1.0</version>
<type>pom</type><scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>同一个依赖可能被多个 BOM 管理,显式依赖版本、导入顺序和父级管理都会影响最终解析结果。检查实际依赖树比只看顶层 POM 更可靠;规则见 Maven 的依赖机制。
后续在相同构建容器中,把 clean verify 替换为下面的目标即可检查解析结果:
mvn -B -ntp -Dmaven.repo.local=/m2 dependency:tree \
-Dincludes=com.alibaba.nacos:nacos-client,com.alibaba.csp:sentinel-core应出现 nacos-client:3.1.1 和 sentinel-core:1.8.9。出现其他版本时先找出覆盖来源。兼容性检查报错也应沿矩阵修正依赖,不应通过关闭检查继续运行。
按业务需要接入组件
| 组件 | 应用侧需要处理的具体工作 | 独立运行的对象 |
|---|---|---|
| Nacos Discovery | 注册实例,查询地址,处理目录更新和下线 | Nacos Server |
| Nacos Config | 导入配置、订阅变更、校验并应用新值 | Nacos Server 与配置管理入口 |
| Sentinel | 定义资源、统计调用、装载规则、处理拒绝 | 保护逻辑在应用内;Dashboard 可单独部署 |
| RocketMQ | 发送确认、消费幂等、重试与积压处理 | Broker 等消息基础设施 |
| Seata | 选择事务模式,处理全局事务与分支事务 | 事务协调服务 |
| SchedulerX | 编写可重入任务,控制并发、重试与调度权限 | 调度服务与应用 Worker |
消息、分布式事务和任务调度各自有持久化与恢复过程,不能用一个注册成功的服务代替它们的验证。SCA 的RocketMQ 接入、Seata 接入与SchedulerX 接入分别给出了对应入口。已经有可靠的消息或调度系统时,可以只接入当前缺少的组件。
配置订阅、服务目录与保护规则如何生效
Nacos 中的地址、命名空间和名称
Nacos 3.1.1 的单机部署要区分以下端口。应用和 Nacos 在同一个 Docker 网络中时,应访问服务名 nacos,不能使用宿主回环地址。
| 端口 | 用途 | 实验中的访问方式 |
|---|---|---|
| 8848 | HTTP Open API、客户端地址入口 | 应用使用 nacos:8848;宿主映射 18848 |
| 9848 | 客户端 gRPC 连接 | 仅容器网络内访问 |
| 8080 | Console | 宿主映射 18880 |
| 9849 等内部端口 | 服务端内部通信 | 不对宿主或公网开放 |
外部 SDK 连接场景还要使推导出的 gRPC 端口可达。仅转发 8848,可能得到“管理 API 可访问,客户端连接失败”的结果。部署说明见Nacos 3.1 Docker 文档。
配置由 namespaceId + group + dataId 定位。命名空间名称供人阅读,客户端使用的是 ID。服务发现使用服务名、group、namespace,并可附带 cluster、权重和实例 metadata;这些信息不替代服务内部的业务鉴权。
namespace ID = ms13 单应用隔离空间
├─ 配置 group = LAB
│ └─ dataId = settings.properties
│ └─ lab.message=green
└─ 服务 group = LAB
└─ serviceName = alibaba-app
└─ cluster = LOCAL,实例地址与端口由应用注册配置从存储值变成对象值需要经过刷新
SCA Nacos 接入文档要求使用 spring.config.import。2025.1.x 已移除 Bootstrap 接入支持;不要再拼接旧教程中的 bootstrap.yml、shared-configs 与新的导入方式。
spring.application.name=alibaba-app
spring.config.import=nacos:settings.properties?group=LAB&refreshEnabled=true
spring.cloud.nacos.server-addr=${NACOS_SERVER_ADDR:nacos:8848}
spring.cloud.nacos.username=${NACOS_USERNAME:lab-app}
spring.cloud.nacos.password=${NACOS_PASSWORD}
spring.cloud.nacos.config.namespace=ms13
spring.cloud.nacos.discovery.namespace=ms13
spring.cloud.nacos.discovery.group=LAB应用启动时拉取配置,导入 Spring Environment;随后 SDK 监听变更,SCA 发布刷新事件。工程中的 MessagePolicy 使用 @RefreshScope,下一次调用获取刷新后的对象。普通对象中已经复制到字段里的值,需要相应的重建或更新机制。
Nacos 接受配置文本,只说明发布操作成功。参数转换、Bean 初始化和业务校验仍可能失败。工程把 lab.message 限制为非空且长度不超过 40,校验发生在应用创建配置对象时;远端编辑器不会替应用执行它。连接池、线程池或证书更换还需要各自的生命周期处理,不能照搬一个字符串的刷新方式。
配置读取权限还要覆盖监听请求
应用使用普通账号 lab-app,管理员账号只用于初始化和发布。Nacos 3.1.1 的批量配置监听按命名空间资源检查权限;仅授予 LAB/settings.properties 读取时,首次拉取可以成功,后续 ConfigBatchListenRequest 却可能持续返回 403。
这个版本的监听处理器与默认鉴权资源拼接解释了检查对象。实验给 lab-app 两项权限:
| 资源 | 动作 | 实际范围 |
|---|---|---|
ms13:*:config/* | r | ms13 内所有配置只读,包含监听所需范围 |
ms13:LAB:naming/alibaba-app | rw | 指定服务注册与查询 |
因此 ms13 只放这个应用的配置,不能混入其他应用的凭据。这是针对该版本默认鉴权实现的实验隔离方式,不是跨产品通用 ACL。Nacos 定位为内网组件,鉴权还需要配合网络隔离;管理端不应暴露公网。Nacos 鉴权说明给出了相应限制。
Sentinel 检查的是应用中定义的资源
greeting 是下面这段保护代码的资源名。SphU.entry 执行规则检查;通过后才读取配置并增加业务计数,结束时必须调用 exit。拒绝分支返回明确的 429。
Entry entry = null;
try {
entry = SphU.entry("greeting");
return ResponseEntity.ok(
Map.of("message", policy.message(), "passed", passed.incrementAndGet()));
} catch (BlockException blocked) {
return ResponseEntity.status(429)
.body(Map.of("error", "SENTINEL_BLOCKED", "resource", "greeting"));
} finally {
if (entry != null) entry.exit();
}资源可以是一次方法调用、远程调用或接口处理片段,不必等于完整 URL。QPS 流控、并发线程数流控、熔断、热点参数规则和系统保护使用不同的统计对象,规则类型应与要保护的资源匹配。手工埋点与规则定义见Sentinel 使用说明。
实验通过 FlowRuleManager.loadRules 在当前进程内装载 QPS 规则。它不经过 Nacos,重启后也不会自动恢复。需要持久化与多实例规则更新时,应接入数据源,把规则发布、应用订阅和加载失败分别观测;机制见动态规则配置与SCA Sentinel 进阶指南。
在 Docker 中接入真实 Nacos 并验证变化
准备工程、身份和密钥
下载完整实验 ZIP,解压后进入 microservice-alibaba-lab,源码与文件说明见其中的 README.md。宿主使用普通 Linux 用户,需要 Bash、Docker Compose、curl、jq、openssl,并能拉取 Maven、Temurin 与 Nacos 镜像。
set -euo pipefail
test "$(id -u)" -ne 0 || exit 1
docker info >/dev/null
docker compose version
curl --version
jq --version
openssl version
test ! -e .env || { printf '.env 已存在,请复用或先归档本实验\n'; exit 1; }
umask 077
{
printf 'NACOS_AUTH_TOKEN=%s\n' "$(openssl rand -base64 48 | tr -d '\n')"
printf 'NACOS_AUTH_IDENTITY_VALUE=%s\n' "$(openssl rand -hex 24)"
printf 'NACOS_ADMIN_PASSWORD=Ms13-%s\n' "$(openssl rand -hex 20)"
printf 'NACOS_APP_PASSWORD=Ms13-%s\n' "$(openssl rand -hex 20)"
} > .env
source .env
mkdir -p .m2.env 不应提交、截图或打印。不要开启 set -x,也不要把含展开后环境变量的 docker compose config 输出贴进工单。Docker 管理权限仍可读取容器环境;生产应使用受控秘密管理设施。
Nacos 派生镜像在构建阶段创建账号与目录,运行时使用 10001:10001。它关闭官方入口脚本的 shell xtrace,并把默认鉴权 DEBUG 日志调为 INFO,以减少凭据输出。只读根文件系统之外,数据、日志和临时目录单独挂载 tmpfs;/tmp 允许执行是 RocksDB JNI 动态库加载所需。应用同样以 10001 运行。
docker compose up -d --build nacos
docker compose logs --tail=30 nacos等待 Nacos Server 与 Console 启动成功。后续初始化仅针对这个全新实验实例,不要指向共享 Nacos。其配置数据在停止后丢失,不适用于生产持久化。
初始化管理员、应用角色和配置
定义隔离客户端状态的请求命令。除 HTTP 成功外,Nacos 包装响应还要检查 code == 0:
BASE=http://127.0.0.1:18848/nacos
CURL=(curl -q --noproxy '*' --connect-timeout 2 --max-time 10 \
--silent --show-error --fail-with-body)
"${CURL[@]}" "$BASE/v3/admin/core/state" \
| jq -e '.code == 0 and .data.version == "3.1.1"'
reply=$("${CURL[@]}" -X POST "$BASE/v3/auth/user/admin" \
--data-urlencode "password=$NACOS_ADMIN_PASSWORD")
jq -e '.code == 0 and .data.username == "nacos"' <<<"$reply" >/dev/null
ADMIN_TOKEN=$("${CURL[@]}" -X POST "$BASE/v3/auth/user/login" \
--data-urlencode username=nacos \
--data-urlencode "password=$NACOS_ADMIN_PASSWORD" | jq -er '.accessToken')
admin_post() {
local reply
reply=$("${CURL[@]}" -H "accessToken:$ADMIN_TOKEN" -X POST "$@")
jq -e '.code == 0' <<<"$reply" >/dev/null
}
admin_post http://127.0.0.1:18880/v3/console/core/namespace \
--data-urlencode customNamespaceId=ms13 \
--data-urlencode namespaceName=ms13 --data-urlencode namespaceDesc=isolated-lab
admin_post "$BASE/v3/auth/user" --data-urlencode username=lab-app \
--data-urlencode "password=$NACOS_APP_PASSWORD"
admin_post "$BASE/v3/auth/role" \
--data-urlencode role=LAB_APP --data-urlencode username=lab-app
admin_post "$BASE/v3/auth/permission" --data-urlencode role=LAB_APP \
--data-urlencode 'resource=ms13:*:config/*' --data-urlencode action=r
admin_post "$BASE/v3/auth/permission" --data-urlencode role=LAB_APP \
--data-urlencode resource=ms13:LAB:naming/alibaba-app --data-urlencode action=rw
admin_post "$BASE/v3/admin/cs/config" \
--data-urlencode namespaceId=ms13 --data-urlencode groupName=LAB \
--data-urlencode dataId=settings.properties \
--data-urlencode content=lab.message=green各步应无错误退出。管理员初始化响应含密码,因此只检查变量,不显示完整响应。登录接口返回顶层 accessToken,与其他接口的 code/data 包装不同。Namespace 创建使用 Console API,其路径与端口也与配置发布不同;参数说明分别见Console API和Admin API。
构建并得到第一次成功
测试会真实连接 Nacos,缺少配置、账号或网络时直接失败,不跳过。构建目录与 Maven 缓存使用宿主 UID/GID;不要通过 root 构建掩盖目录不可写。
docker run --rm --network ms13-alibaba \
--user "$(id -u):$(id -g)" \
-e MAVEN_CONFIG=/m2 -e MAVEN_OPTS=-Duser.home=/tmp \
-e NACOS_SERVER_ADDR=nacos:8848 -e NACOS_USERNAME=lab-app \
-e NACOS_PASSWORD="$NACOS_APP_PASSWORD" \
-v "$PWD:/work" -v "$PWD/.m2:/m2" -w /work \
maven:3.9.12-eclipse-temurin-25 \
mvn -B -ntp -Dmaven.repo.local=/m2 clean verify
docker compose up -d app
docker compose logs --tail=30 app构建应得到 4 个通过的测试及 target/alibaba-app.jar。等待应用日志出现 Started AlibabaApplication,再请求:
APP=http://127.0.0.1:18191
"${CURL[@]}" "$APP/hello" | jq -e '.message == "green"'
"${CURL[@]}" "$APP/lab/instances" \
| jq -e 'length >= 1 and .[0].serviceId == "alibaba-app"'第一条返回类似 {"message":"green","passed":1},计数随请求递增。第二条包含注册到 Nacos 的真实容器地址与 8080 端口,不应固定比对某个 IP。这里只查询目录;调用方拿到地址后仍需连接,负载选择的过程见负载均衡、超时与重试。
发布配置,观察应用随后更新
admin_post "$BASE/v3/admin/cs/config" \
--data-urlencode namespaceId=ms13 --data-urlencode groupName=LAB \
--data-urlencode dataId=settings.properties \
--data-urlencode content=lab.message=blue
seen=false
for ((i=0;i<100;i++)); do
message=$("${CURL[@]}" "$APP/hello" | jq -r '.message')
if test "$message" = blue; then seen=true; break; fi
sleep .1
done
test "$seen" = true应在有限等待内看到 blue,不需要调用 Actuator refresh。短暂看到旧值符合异步传播过程;一直不变时,依次比较配置中心内容、SDK 监听响应和应用刷新日志。
用真实限流规则拒绝请求,再恢复
将 greeting 的 QPS 配额改为 0,便于稳定复现拒绝。管理端点只用于隔离实验,不应原样上线。
"${CURL[@]}" -X POST "$APP/lab/rules?count=0" \
| jq -e '.source == "LOCAL_MEMORY"'
before=$("${CURL[@]}" "$APP/lab/counts" | jq -r '.passed')
transport=0
status=$(curl -q --noproxy '*' --connect-timeout 2 --max-time 10 -sS \
-o .lab-denied.json -w '%{http_code}' "$APP/hello") || transport=$?
test "$transport" -eq 0 && test "$status" = 429
jq -e '.error == "SENTINEL_BLOCKED"' .lab-denied.json
after=$("${CURL[@]}" "$APP/lab/counts" | jq -r '.passed')
test "$before" = "$after"
"${CURL[@]}" -X POST "$APP/lab/rules?count=100" >/dev/null
"${CURL[@]}" "$APP/hello" | jq -e '.message == "blue"'429 和计数未增长一起表明拒绝发生在业务计数之前。配额 100 仅表示当前进程该资源的允许量,两个实例各设 100 不会自然形成全局 100。需要全局限流时应采用相应的集中或集群方案,并处理计数服务不可用时的行为。
根据失败位置处理权限、配置和运行问题
普通应用账号必须无法发布配置
换成 lab-app 的 Token,向同一配置发起写入:
APP_TOKEN=$("${CURL[@]}" -X POST "$BASE/v3/auth/user/login" \
--data-urlencode username=lab-app \
--data-urlencode "password=$NACOS_APP_PASSWORD" | jq -er '.accessToken')
transport=0
status=$(curl -q --noproxy '*' --connect-timeout 2 --max-time 10 -sS \
-o .lab-denied.json -w '%{http_code}' -X POST "$BASE/v3/admin/cs/config" \
-H "accessToken:$APP_TOKEN" \
--data-urlencode namespaceId=ms13 --data-urlencode groupName=LAB \
--data-urlencode dataId=settings.properties \
--data-urlencode content=lab.message=unauthorized) || transport=$?
test "$transport" -eq 0 && test "$status" = 403
jq -e '.message | contains("authorization failed")' .lab-denied.json
"${CURL[@]}" "$APP/hello" | jq -e '.message == "blue"'传输成功、HTTP 403、鉴权错误正文和应用值保持不变共同验证这条限制。只检查“不是 200”会把连错端口也当成权限测试通过。
错误密码可能被上层包装为配置不存在
启动一个使用错误密码的一次性应用:
result=0
docker compose run --rm --no-deps \
-e NACOS_PASSWORD=intentionally-wrong app || result=$?
test "$result" -ne 0在这套组合中,应用非零退出,顶部故障说明可能写 Config data resource ... does not exist。这个提示也可能来自读取失败,不能仅凭字面删除或重建配置。先确认管理员能读取目标,再查看 SDK 的登录与配置请求结果。不要按提示直接加 optional::这个应用需要远端配置才能工作。
正确的 .env 没有被一次性容器覆盖,正常实例继续运行。需要验证恢复时可执行 docker compose up -d app,重新检查 /hello。
沿实际对象定位
| 现象 | 优先检查 | 修正后观察 |
|---|---|---|
| 缺类、NoSuchMethodError | 实际依赖树、BOM 覆盖、适配矩阵 | 清理构建并重跑协议与启动测试 |
| 管理 API 可访问,SDK 超时 | 8848 地址、9848 可达性、容器 DNS | 客户端连接与注册/配置读取成功 |
| 初始配置正常,发布后长期不变 | namespace ID、group、dataId、监听 403、RefreshScope | 新值实际参与请求处理 |
| Actuator UP,但 Nacos 不可用 | HealthIndicator 开关、已有快照、连接状态 | 单独读取配置与查询目录 |
| 管理页面有规则,业务未受限 | 资源名、规则类型、实例、数据源装载状态 | 拒绝统计和业务调用数发生预期变化 |
| Nacos 只读运行失败 | Derby 日志目录、data 权限、JNI 临时目录执行权限 | Server/Console 正常启动,无同类异常 |
SCA 2025.0 起默认关闭 Nacos 的 Config 与 Discovery HealthIndicator,上面的接入文档明确说明了开关。即使显式开启,也应根据探测用途决定是否把注册中心暂时故障纳入应用 readiness,避免所有已运行实例同时被摘除。
配置回退仍是一次发布。恢复 green 后,应等实际请求读到该值,再结束实验:
admin_post "$BASE/v3/admin/cs/config" \
--data-urlencode namespaceId=ms13 --data-urlencode groupName=LAB \
--data-urlencode dataId=settings.properties \
--data-urlencode content=lab.message=green
for ((i=0;i<100;i++)); do
message=$("${CURL[@]}" "$APP/hello" | jq -r '.message')
test "$message" = green && break
sleep .1
done
test "$message" = green
rm -f -- .lab-denied.json
docker compose down
unset ADMIN_TOKEN APP_TOKEN NACOS_ADMIN_PASSWORD NACOS_APP_PASSWORD这会删除实验容器与网络;tmpfs 中的 Nacos 配置、账号与日志一并消失。.env、源码、JAR 和 Maven 缓存留在本机,仍需妥善保管或按实验目录处理。再次启动 Nacos 时要重新初始化。生产部署则应先规划持久化、集群、备份恢复、连接容量与访问控制,再进行滚动升级。
