此处会列出关于 Sentinel 的常见问题以及相应的注意事项和解决方案。
配置相关
Q: 配置参数如何指定?
A: 可通过 JVM -D 参数指定。除 project.name
之外,其余参数还可通过 properties 文件指定,路径为 ${home}/logs/csp/${project.name}.properties
。详见 启动项配置文档。
Q: 可否自定义 properties 文件的位置或日志文件的位置?
A: 1.3.0 版本开始支持配置日志文件的目录,可以参考 启动项配置文档;若希望自定义 properties 文件的位置或使用其它的加载方式,可以结合 Spring Cloud Alibaba Sentinel 使用。
Sentinel 核心功能相关
Q: Sentinel 可否用于生产环境?
A: 当然可以!Sentinel 可用于生产环境,但若要在生产环境中使用 Sentinel 控制台则还需要进行一些改造,可以参考:在生产环境中使用 Sentinel 控制台。
Q: 想从 Hystrix 迁移到 Sentinel,有没有相关指南?
A: 可以参考 Guideline: 从 Hystrix 迁移到 Sentinel。
Q: 我的服务是基于 Spring Boot 和 Dubbo 编写的,可以直接用 Sentinel 吗?
A: 当然啦,Sentinel 针对常用框架和库进行了适配,包括 Web Servlet、Dubbo、Spring Boot / Spring Cloud、gRPC 等,可以参见 主流框架的适配。
Q: Sentinel 的性能如何?只进行资源定义不配置规则,仅统计指标信息会有多少性能损耗?
A: 引入 Sentinel 带来的性能损耗非常小。只有在业务单机量级超过 25W QPS 的时候才会有一些显著的影响(10% 左右),单机 QPS 不太大的时候损耗几乎可以忽略不计。性能测试报告见 Benchmark。
Q: 是否需要在初始化时手工调用 InitExecutor.doInit()
方法进行相应的初始化?
A: 不需要,sentinel-core 的 Env
类通过 static 块调用了此方法进行初始化,在首次调用资源时即可触发。一些 demo 中手动调用此方法是为了不让进程退出或提前进行初始化。
Q: 规则生效后,除了抛异常之外还有没有其它的处理方式?
A: 有以下几种情况:
- 默认资源被流控降级后会抛出
BlockException
异常的子类(比如限流会抛FlowException
异常,降级会抛出降级异常DegradeException
)。您可以通过以下方法判断是否为流控降级异常:BlockException.isBlockException(Throwable t)
。 - 对于 Sentinel 注解模式,可以在
@SentinelResource
注解上配置blockHandler
函数(注意对应函数的签名需要符合要求),在被限流降级的时候进行相应的处理。 - 对于 Dubbo 服务,我们支持注册全局的 fallback 函数,可参考 Dubbo 适配文档。
- Web Servlet Filter:默认情况下,当请求被限流时会返回默认的提示页面,提示信息为:
Blocked by Sentinel (flow limiting)
。您也可以通过WebServletConfig.setBlockPage(blockPage)
方法设定自定义的跳转 URL,当请求被限流时会自动跳转至设定好的 URL。同样也可以实现UrlBlockHandler
接口并编写定制化的限流处理逻辑,然后将其注册至WebCallbackManager
中。详情可参考 Web Servlet Filter 扩展文档。
Q: 怎么针对特定调用端限流?比如我想针对某个 IP 或者来源应用进行限流?规则里面 limitApp(流控应用)的作用?
A: Sentinel 支持按来源限流,可以参考 基于调用关系的限流。注意 origin 数量不能太多,否则会导致内存暴涨,并且目前不支持模式匹配。
若 Web 应用使用了 Sentinel Web Filter,并希望对 HTTP 请求按照来源限流,则可以自己实现 RequestOriginParser
接口从 HTTP 请求中解析 origin 并注册至 WebCallbackManager
中。示例代码:
- WebCallbackManager.setRequestOriginParser(ServletRequest::getRemoteAddr);
特别地,流控应用如果使用了 Sentinel Dubbo Adapter,同时 Dubbo 的消费者也引入了 Sentinel Dubbo Adapter(用于透传 dubboApplication
这个参数),则填 Dubbo 调用方的 application name 就好(注意是 Dubbo 里配置的应用名而不是 Sentinel 的应用名),消费端引入 adapter 就会自动透传,否则需要自己传来源应用名。
注意来源信息(origin
)一般是在入口处传入的(如 HTTP 入口或 Dubbo 服务入口),因此在链路中间再通过 ContextUtil.enter(xxx, origin)
传入可能不会生效。
Q: 很多开发通过错误码或者 HTTP 响应状态码来处理流程,而非通过异常。这种写法导致 Sentinel 不能记录为异常请求,无法触发熔断降级。对于这种情况,有没有什么好的处理方法?
A: 实际上 Sentinel 是通过 Tracer.traceEntry(ex, entry)
方法来统计业务异常的,因此可以收到错误码就调用此函数来自行记录为业务异常。
Q: 入口资源和出口资源是什么意思?EntryType.IN 有什么作用?
A: 入口流量指的是进入应用的流量(EntryType.IN
),通常作为 provider。比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。而出口流量指的是从本资源调其它资源的流量(EntryType.OUT
),通常作为 consumer。
部分规则的判断会区分流量类型,比如系统规则只对入口流量生效。
Q: 手动通过 SphU.entry(xxx)
进行埋点具有侵入性,有没有低侵入性的方案?
A: 可以利用 Sentinel 注解支持 或者 各种框架的适配。
Q: Sentinel 未来会考虑支持分布式链路调用跟踪吗?
A: Sentinel 的核心功能是流量控制和限流降级。分布式链路调用跟踪不是 Sentinel 关注的功能,可以参考其它分布式链路调用跟踪系统。
Q: Sentinel 支持集群限流吗?
A: 1.4.0 版本开始已经支持,可以参考 集群流控文档。
Q: Sentinel 支持 reactive 应用吗(比如用了 Spring WebFlux 或者 Reactor 之类的)?
A: Sentinel 1.5.0 开始提供 Reactor 的适配模块,可以参考 Sentinel Reactor Adapter 文档。
Q: Web 端的资源目前都是根据某个特定的 URL 限流,可不可以根据前缀匹配限流?
A: 对于 Sentinel Web Servlet Filter,可以借助 UrlCleaner
处理对应的 URL(如提取前缀的操作),这样对应的资源都会归到处理后的资源(如 /foo/1
和 /foo/2
都归到 /foo/*
资源里面)。UrlCleaner
实现 URL 前缀匹配只是个 trick,它会把对应的资源也给归一掉,直接在资源名粒度上实现模式匹配还是有很多顾虑的问题的。
Sentinel 集群限流相关
Q: 集群限流没有生效?
A: 请参考以下步骤排查:
- 请确保接入端引入了 Sentinel 集群流控相关的依赖;
- 检查
~/logs/csp/sentinel-record.log
查看 Token Server / Client 是否加载成功,是否成功启动;动态规则源是否注册成功,接入端规则和 Token Server 集群规则是否都接收成功; - 在 Token Client 端检查
~/logs/csp/sentinel-cluster-client.log
日志,看一下是否是 Token Server 未启动或者规则未接收到的问题; - 若从开源 Sentinel 控制台推送集群规则,请务必确保按照 Sentinel 集群流控控制台文档 进行了相应改造,并且接入端按照 集群规则配置文档 配置了相关动态规则源;
Q: 集群限流有时候会超过设定的总体阈值?
A: 偶尔的、少量的超出阈值是正常的。Sentinel 是非严格限流,兼顾性能与准确性。
Q: 通过 Sentinel 控制台或 API 来分配管理 Token Server 时,返回错误:token client/server mode not available: no SPI found
A: 请确保接入端引入了 Sentinel 集群流控相关的依赖(嵌入模式两者都需要):
- Token Client:
sentinel-cluster-client-default
- Token Server:
sentinel-cluster-server-default
更多信息可参见 集群流控文档。
Q: 集群流控规则中“单机均摊”阈值模式是什么意思?
A: 单机均摊模式下配置的阈值等同于单机能够承受的平均限额。Token Server 会根据客户端对应的 namespace(默认为 project.name
定义的应用名)下的连接数来计算总的阈值(比如独立模式下有 3 个 client 连接到了 token server,然后配的单机均摊阈值为 10,则计算出的集群总量就为 30)。单机均摊阈值仅用于计算总体阈值,不是说每台机器一定要控制在均摊阈值上。配置方式:若希望某个资源限制集群总量为 Q,服务实例为 N,则可以配置单机均摊阈值为 Q / N
。
Q: 集群流控 Token Server 中的 namespace set 有什么用处?
A: namespace set 即 Token Server 服务的作用域(命名空间集合),用于指定该 Token Server 可以为哪些应用提供集群流控服务,一般设置为接入端应用名的集合。Token Client 在连接到 token server 后会上报自己的命名空间(默认为 project.name
配置的应用名),token server 会根据上报的命名空间名称统计连接数。
- 嵌入模式下一般仅服务自身,默认嵌入模式的 namespace set 为该应用本身
- 所有 Token Server 都自带一个默认的命名空间
default
,一般情况下不会用到
Sentinel Transport/Dashboard 相关
Q:Sentinel Transport 同一台机器起相同的端口不报错?如果几个应用都没配 csp.sentinel.api.port
会出错吗?
A: 对于 sentinel-transport-simple-http
,默认 8719 端口被占用以后会自动选择下一个端口,直到有可用的端口为止。选择端口时间会比较长,本地如果起多个应用建议自己通过 csp.sentinel.api.port
设置端口。
Q: 为什么 Sentinel Transport 模块里自己用原生 Socket 或 Netty 自己实现的 HTTP Server,为什么不用 Web 容器(如 Tomcat)?
A: 使用 Web 容器作为一个组件来说太过于重量级了,因此我们自己实现了简单的 sentinel-transport-simple-http
和 sentinel-transport-netty-http
模块,两个模块的功能是相同的,一般用 sentinel-transport-simple-http
即可,而 sentinel-transport-netty-http
是为了后续的可扩展性和兼容性而设计的。
Q: 目前 Sentinel Transport 里面可否自己扩展添加 command?
A: 可以的,用户可以自行实现 CommandHandler
接口,并在实现类上加上 @CommandMapping
注解(代表 command name)。接着在资源目录下的 META-INF/services
目录下添加 com.alibaba.csp.sentinel.command.CommandHandler
文件(如果没有的话),在文件里加上自己的实现类的全名即可。比如:
- package io.test;
- @CommandMapping(name = "test")
- public class TestCommandHandler implements CommandHandler<String> {
- @Override
- public CommandResponse<String> handle(CommandRequest request) {
- return CommandResponse.ofSuccess("666");
- }
- }
在自己项目目录下的 resources/META-INF/services/com.alibaba.csp.sentinel.command.CommandHandler
文件中添加:
io.test.TestCommandHandler
这样初始化 Sentinel Transport Server 的时候,对应的 command 就会自动注册,可以通过 curl host:ip/test
来验证是否成功。
Q: 想要在生产环境中使用 Sentinel 控制台,还需要进行哪些改造?
A: 在生产环境中使用 Sentinel 控制台需要考虑下面的问题:
- 监控数据持久化
- 规则推送支持应用维度,并且整合配置中心以便可以直接推送至远程配置中心
- 权限控制(1.6.0 引入了基本的登录功能) 详细指南请参考此 blog: 在生产环境中使用 Sentinel 控制台。
Q: 已经引入了适配模块(比如 sentinel-dubbo-adapter),然而在 Sentinel 控制台上没有找到我的应用?
A: 请确保对应的依赖和参数配置正确。接入控制台需要上报的客户端依赖,如 sentinel-transport-simple-http
,不引入相关依赖则无法将相关信息上报到控制台。参数配置详情请参考 Sentinel 控制台文档。
详细的排查步骤请见下面。
Q: Sentinel 控制台没有显示我的应用,或者没有监控展示,如何排查?
A: Sentinel Dashboard 是一个单独启动的控制台,应用若想上报监控信息给 Sentinel 控制台,需要引入 Sentinel 上报信息的 transport 模块。它们各自有自己的通信端口,其中控制台的端口可通过启动参数 -Dserver.port=xxxx
进行配置,而 Sentinel transport 模块的端口可以通过启动参数 -Dcsp.sentinel.api.port
进行配置(默认是 8719)。两者都启动之后,Sentinel 客户端在首次访问资源时会初始化并给控制台发送心跳,之后控制台会通过接入端提供的端口对 Sentinel 进行访问来拉取相关信息。基于此,接入控制台需要的步骤如下:
- 接入 Sentinel 的应用应该引入 Sentinel 客户端通信的基础 jar 包,如
sentinel-transport-simple-http
- 客户端启动时添加相应的 JVM 参数,包括:
- 应用名称:
-Dproject.name=xxxx
(会显示在控制台) - 控制台地址:
-Dcsp.sentinel.dashboard.server=ip:port
- 本地的 Sentinel 客户端端口:
-Dcsp.sentinel.api.port=xxxx
(可选,默认是 8719,有冲突会尝试向后探测) - 详细参数配置详情请参考 Sentinel 控制台文档。
- 应用名称:
启动控制台,运行应用,当首次访问对应的资源后 等待一段时间即可在控制台上看到对应的应用以及相应的监控信息。可以通过
curl http://ip:port/tree
命令查看调用链,正常情况下会显示出已访问资源的调用链。 注意:Sentinel 会在客户端首次调用时候进行初始化,开始向控制台发送心跳包。因此需要确保客户端有访问量,才能在控制台上看到监控数据。另外,还是期待大家养成看日志的好习惯,详见 日志文档。控制台推送规则的日志默认位于控制台机器的
${user.home}/logs/csp/sentinel-dashboard.log
- 接入端接收规则日志默认位于接入端机器的
${user.home}/logs/csp/sentinel-record.log.xxx
接入端 transport server 日志默认位于接入端机器的
${user.home}/logs/csp/command-center.log.xxx
常用排查问题列表:确认 Dashboard 已经正常启动并可以正常访问
- 检查网络配置、防火墙配置,确认控制台与接入端服务双向的网络是否连通
- 若是 Spring Boot / Dubbo 等应用,请务必检查是否引入了整合依赖(如 Dubbo 对应
sentinel-dubbo-adapter
)并进行了相应配置 - 检查接入端的启动参数配置是否正确(如控制台地址是否配置正确)
- 通过
~/logs/csp/sentinel-record.log
日志排查客户端发送心跳包是否正常,是否正常上报给 Dashboard - 确保 fastjson 的版本和 Sentinel 的依赖版本保持一致
- 通过
curl IP:port/getRules?type=flow
等命令查看结果,查看规则是否推送成功 - 发送到客户端的规则格式是否正确
- 若控制台已正常显示应用,但看不到监控、请求链路,机器列表页面显示的 IP 不正确,可以参考 此 issue。
Q: 客户端和控制台不在一台机器上,客户端成功接入控制台后,控制台无法显示实时的监控数据?但簇点链路页面有实时请求数据(不为 0)?
A: 请确保 Sentinel 控制台所在的机器时间与自己应用的机器时间保持一致(通过 NTP 等同步)。Sentinel 控制台是通过控制台所在机器的时间戳拉取监控数据的,因此时间不一致会导致拉不到实时的监控数据。
Q: 控制台正确的规则推送后看不到?
客户端成功接入控制台后,控制台配置规则准确无误,但是客户端收不到规则或者报错?比如配置的资源名正确但 sentinel-record.log
日志里面却报 resourceName 为空的错误?
A: 排查客户端是否使用了低版本的 fastjson,低版本的 fastjson 可能会有此问题,建议使用和 Sentinel 相关组件一致版本的 fastjson。
Q: Sentinel 监控数据能保留多久?控制台聚合的统计数据可否进行持久化?
A: Sentinel 对监控数据的做法是定时落盘在客户端,然后 Sentinel 提供接口去拉取日志文件。所以 Sentinel 在监控数据上理论上是最少存储 1 天以上的数据;然而作为控制台展示,则仅在内存中聚合 5 分钟以内的统计数据,不进行持久化。
我们鼓励大家对 Dashboard 进行改造实现指标信息的持久化,并从其它的存储中(如 RDBMS、时序数据库等)拉取的监控信息,包括实时的和历史的数据。
Q: Sentinel 控制台有登录或者细粒度的权限控制功能吗?
A: 目前 Sentinel 支持简单的登录功能。Sentinel 控制台提供权限控制接口(AuthService),但具体的权限控制实现需要自己去定制。
Q: Sentinel Dashboard 中簇点链路页面里面资源名称为什么会有重复的?
A: 最顶层的是 Context 名,用于区分不同调用链路(入口)。
Q: 应用已经退出了,Sentinel 控制台的应用列表里还有显示?
A: 若应用已退出,过 1 分钟没有收到心跳,控制台就会标记对应机器为失联状态,但不会将对应应用从列表中移除。
Q: 为什么说 Sentinel 控制台集群资源汇总仅支持 500 台以下的应用集群?
A: 因为 Sentinel 控制台仅作为示范,其监控聚合能力非常有限,但是应用端是没有限制的。若希望支持更多的机器,可以使用动态规则数据源并改造控制台,同时改造实现监控数据持久化,部署控制台集群。
Q: Sentinel 控制台规则配置里面“流控应用”是什么?
A: 对应规则中的 limitApp
,即请求来源,通过入口处 ContextUtil.enter(contextName, origin)
中的 origin
传入。参见上面的“按调用方进行限流”。
Q: 控制台推送规则失败,报 com.alibaba.csp.sentinel.dashboard.client.CommandFailedException: invalid type 错误?
A: 可能是 Sentinel 相关依赖版本不一致导致的。可以参考:https://github.com/alibaba/Sentinel/issues/924
规则存储与动态规则数据源(DataSource)
Q: 动态规则数据源分为哪几种?各自的使用场景?
A: 数据源分为只读的数据源和可写入的数据源。
- 可写入的数据源一般对应 pull 模式的数据源(如本地文件、RDBMS),从控制台推送规则时可先经 Sentinel 客户端更新到内存中,然后经注册的
WritableDataSource
写入到本地。 - 只读的数据源一般对应 push 模式的数据源(如配置中心等)。对于配置中心,写入的操作不应由数据源进行,数据源仅负责获取配置中心推送的配置并更新到本地。从控制台推送规则的次序应该是 配置中心控制台/Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel,而不是经 Sentinel 数据源推送至配置中心。注意由于不同的生产环境可能使用不同的数据源,从 Sentinel 控制台推送至配置中心的实现需要用户自行改造。
Q: 在控制台配置的规则存在哪里?为什么应用重启规则就消失了?
A: 在控制台配置的规则是存在内存里面的,没有进行持久化,因此应用重启后规则就消失了。
可以参考 动态规则文档 持久化存储规则。
Q: 我在客户端处配置了动态规则数据源(如基于 ZooKeeper / Nacos / Apollo 的数据源),然后在控制台处向客户端推送了规则,但是规则并没有写入到对应的数据源中?
A: push 模式的数据源(如配置中心)都是只读的。对于配置中心类型的数据源(如 ZooKeeper),我们推荐在推送规则时直接推送至配置中心,然后配置中心再自动推送至所有的客户端(即 Dashboard -> Config Center -> Sentinel DataSource -> Sentinel
),目前需要自行改造控制台。可以参见:在生产环境中使用 Sentinel 控制台。
对于 pull 模式的数据源(如本地文件),则可以向 transport-common 模块的 WritableDataSourceRegistry
注册写入数据源,在推送规则时会一并推送至本地数据源中。
其它
Q: 引了 Spring Cloud Alibaba 的相关依赖以后,再引高版本的 Sentinel 依赖会报错?
A: spring-cloud-alibaba-dependencies
里面会限定 Sentinel 的依赖版本,导致不同 Sentinel 模块之间的版本不一致,可能会有兼容问题。可以去掉 dependencyManagement
里面的 spring-cloud-alibaba-dependencies
,或者在自己项目的 pom 文件中强制统一相关依赖的版本:
- <dependencyManagement>
- <dependencies>
- <!-- 保持几个依赖版本统一 -->
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-core</artifactId>
- <version>1.6.3</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-transport-common</artifactId>
- <version>1.6.3</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-datasource-extension</artifactId>
- <version>1.6.3</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-parameter-flow-control</artifactId>
- <version>1.6.3</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-api-gateway-adapter-common</artifactId>
- <version>1.6.3</version>
- </dependency>
- </dependencies>
- </dependencyManagement>
Q: 编译打包的时候 Maven 报错?
A: 请参考以下解决方案:
- 如果是很诡异的错误,请将 Maven 版本升级至较新版本(3.5.x)再进行构建,看看是否有问题。
Q: 编译时或者 CI 跑测试用例会出现偶尔无法通过的情况?
A:有少数的基于 sleep 的测试用例可能会有不稳定的情况,这时候只需要重试几次即可成功。
致谢
感谢以下热心贡献者参与整理(排名不分先后):宸明,谢佶含