“Sentinel控制台页面中的微服务数据空白” 问题的处理
整合步骤完成后,发现 Sentinel
控制台页面中的微服务数据空白,意外的问题出现了。写案例的时候正常,一放到具体的项目里就不能正常使用了。
紧接着,开始检查代码,看是不是配置有问题,结果一切正常。之后又刷新了 Maven
依赖,重启项目和 Sentinel Server
,问题依然存在。
错误的解决思路
这个时候,笔者尝试了修改配置项,不使用懒加载的方式,在微服务实例启动时就将信息上报给 Sentinel
控制台,于是在配置文件中增加了如下配置项:
spring.cloud.sentinel.eager=true
再次重启项目,进入 Sentinel
控制台,页面左侧的微服务名称出现了,如图 11-2 所示。

微服务数据虽然出现了,但是每个微服务中 “实时监控”、“簇点数据” 页面中的数据都是空的,如图 11-3 所示。

不管发起多少次请求,这些页面都空空如也。因此,微服务架构项目中整合 Sentinel
还是有问题,根本没有监控到任何数据。此时,笔者推测出两个问题:一是实例中的 Sentinel Client
与 Sentinel Server
间的通信有问题,二是实例中的 Sentinel Client
根本没有向 Sentinel Server
上报实例的监控信息。
在 Sentinel
控制台左侧的微服务列表中,单击 “机器列表” 选项,可以看到微服务实例的信息,而且微服务实例与 Sentinel Server
都部署在本地,也就是同一个网络环境中,通信肯定不存在问题。那么很大的可能就是 Sentinel Client
向 Sentinel Server
上报实例的监控信息步骤时出现了问题。
笔者查看实例的启动日志,发现了一条警告级别的日志(不是报错日志):
Bean 'com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration' of type [com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
当时,笔者觉得这可能是个突破口,于是按照这条日志查询了相关的问题,并尝试着解决 “Sentinel
控制台页面中微服务数据空白” 的问题,但花了不少时间,尝试了好几种解决方案,都无功而返。
好了,以上就是笔者对这个问题的错误思路,花了不少时间,但是都没能处理好,这里就不再赘述了。
正确的解决思路
开发人员应该都有过 “发现了问题却不知道如何下手才能解决” 的无力感,整个人都会变得焦躁起来。
当感觉可能解决不了问题的时候,笔者忽然想到是不是自己的思路错了?犹记得之前整合 Seata
时也出现了类似的情况,最后发现问题就是没有配置拦截器而已。这次不会又如此吧!于是,笔者赶紧查了一下 spring-cloud-starter-alibaba-sentinel
的源代码,如图 11-4 所示,最终发现依然是拦截器失效的问题。
因为 newbee-mall-cloud-user-web
、newbee-mall-cloud-recommend-web
、newbee-mall-cloud-order-web
、newbee-mall-cloud-shop-cart-web
和 newbee-mall-cloud-goods-web
5 个微服务实例工程中都自定义了 xxxWebMvcConfigurer
,如果想要 Sentinel
中的这个拦截器生效,就需要分别在各个微服务实例中定义,代码修改如下:

UserServiceWebMvcConfigurer
代码如下:
@Configuration
public class UserServiceWebMvcConfigurer extends WebMvcConfigurationSupport {
private static final Logger log = LoggerFactory.getLogger(UserServiceWebMvcConfigurer.class);
@Autowired
private SentinelProperties sentinelProperties;
@Autowired
private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
@Autowired
private TokenToAdminUserMethodArgumentResolver tokenToAdminUserMethodArgumentResolver;
@Autowired
private TokenToMallUserMethodArgumentResolver tokenToMallUserMethodArgumentResolver;
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(tokenToAdminUserMethodArgumentResolver);
argumentResolvers.add(tokenToMallUserMethodArgumentResolver);
}
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.
addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.resourceChain(false);
}
public void addInterceptors(InterceptorRegistry registry) {
// 配置 Sentinel 拦截器
if (this.sentinelWebInterceptorOptional.isPresent()) {
SentinelProperties.Filter filterConfig = this.sentinelProperties.getFilter();
registry.addInterceptor((HandlerInterceptor) this.
sentinelWebInterceptorOptional.get())
.order(filterConfig.getOrder())
.addPathPatterns(filterConfig.getUrlPatterns());
log.info("[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}", filterConfig.getUrlPatterns());
}
}
}
RecommendServiceWebMvcConfigurer
代码如下:
@Configuration
public class RecommendServiceWebMvcConfigurer extends WebMvcConfigurationSupport {
private static final Logger log = LoggerFactory.getLogger(RecommendServiceWebMvcConfigurer.class);
@Autowired
private SentinelProperties sentinelProperties;
@Autowired
private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
@Autowired
private TokenToAdminUserMethodArgumentResolver tokenToAdminUserMethodArgumentResolver;
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(tokenToAdminUserMethodArgumentResolver);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.
addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.resourceChain(false);
}
public void addInterceptors(InterceptorRegistry registry) {
// 配置 Sentinel 拦截器
if (this.sentinelWebInterceptorOptional.isPresent()) {
SentinelProperties.Filter filterConfig = this.sentinelProperties.getFilter();
registry.addInterceptor((HandlerInterceptor) this.sentinelWebInterceptorOptional.get())
.order(filterConfig.getOrder())
.addPathPatterns(filterConfig.getUrlPatterns());
log.info("[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}", filterConfig.getUrlPatterns());
}
}
}
OrderServiceWebMvcConfigurer
代码如下:
@Configuration
public class OrderServiceWebMvcConfigurer extends WebMvcConfigurationSupport {
private static final Logger log = LoggerFactory.getLogger(OrderServiceWebMvcConfigurer.class);
@Autowired
private SentinelProperties sentinelProperties;
@Autowired
private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
@Autowired
private TokenToAdminUserMethodArgumentResolver tokenToAdminUserMethodArgumentResolver;
@Autowired
private TokenToMallUserMethodArgumentResolver tokenToMallUserMethodArgumentResolver;
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(tokenToAdminUserMethodArgumentResolver);
argumentResolvers.add(tokenToMallUserMethodArgumentResolver);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.resourceChain(false);
}
public void addInterceptors(InterceptorRegistry registry) {
// 配置 Sentinel 拦截器
if (this.sentinelWebInterceptorOptional.isPresent()) {
SentinelProperties.Filter filterConfig = this.sentinelProperties.getFilter();
registry.addInterceptor((HandlerInterceptor) this)
.order(filterConfig.getOrder())
.addPathPatterns(filterConfig.getUrlPatterns());
log.info("[Sentinel Starter] Register SentinelWebInterceptor with urlPatterns: {}.", filterConfig.getUrlPatterns());
}
}
}
ShopCartServiceWebMvcConfigurer
代码如下:
@Configuration
public class ShopCartServiceWebMvcConfigurer extends WebMvcConfigurationSupport {
private static final Logger log = LoggerFactory.getLogger
(ShopCartServiceWebMvcConfigurer.class);
@Autowired
private SentinelProperties sentinelProperties;
@Autowired
private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
@Autowired
private TokenToMallUserMethodArgumentResolver tokenToMallUserMethodArgumentResolver;
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(tokenToMallUserMethodArgumentResolver);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjar/springfox-swagger-ui/")
.resourceChain(false);
}
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SeataHandlerInterceptor())
.addPathPatterns("/**");
// 增加对 Sentinel 拦截器的配置
if (this.sentinelWebInterceptorOptional.isPresent()) {
SentinelProperties.Filter filterConfig =
this.sentinelWebInterceptorOptional.get().getFilter();
registry.addInterceptor((HandlerInterceptor) this.sentinelWebInterceptorOptional.get())
.order(filterConfig.getOrder())
.addPathPatterns(filterConfig.getUrlPatterns());
log.info("[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}.", filterConfig.getUrlPatterns());
}
}
}
GoodsServiceWebMvcConfigurer
代码如下:
@Configuration
public class GoodsServiceWebMvcConfigurer extends
WebMvcConfigurationSupport {
private static final Logger log = LoggerFactory.getLogger(GoodsServiceWebMvcConfigurer.class);
@Autowired
private SentinelProperties sentinelProperties;
@Autowired
private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
@Autowired
private TokenToAdminUserMethodArgumentResolver tokenToAdminUserMethodArgumentResolver;
@Autowired
private TokenToMallUserMethodArgumentResolver tokenToMallUserMethodArgumentResolver;
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(tokenToAdminUserMethodArgumentResolver);
argumentResolvers.add(tokenToMallUserMethodArgumentResolver);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.resourceChain(false);
}
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SeataHandlerInterceptor());
// 增加对Sentinel 埋点或者流控的配置
if (this.sentinelWebInterceptorOptional.isPresent()) {
SentinelProperties.FilterConfig filterConfig = this.sentinelWebInterceptorOptional.getFilter();
registry.addInterceptor((HandlerInterceptor) this.sentinelWebInterceptorOptional.get())
.order(filterConfig.getOrder())
.addPathPatterns(filterConfig.getUrlPatterns());
log.info("[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}, filterConfig.getUrlPatterns());
}
}
}
修改完成后,重启所有的微服务实例。访问后,所有的服务信息都出现在 SentinelDashboard
左侧的列表中,并且 “实例监控”、“簇点链路” 等信息都正常显示,如图 11-5 所示。

“Sentinel Dashboard 页面中微服务数据空白” 的问题解决了。到这里,才算真正地把 Sentinel
整合到微服务架构项目中。之后,就可以对一些资源进行限流配置及降级熔断配置了。
扩展一下这个知识点,除未配置 Sentinel
拦截器会出现 “Sentinel Dashboard 页面中微服务数据空白” 的问题外,还有如下几种情形也会出现该问题。
-
代码配置错误或配置项有遗漏,导致页面空白。解决办法:检查配置,主要是
IP
地址和端口号,若因为粗心漏掉了一些,修改正确即可。 -
默认的懒加载原因,导致页面空白。解决办法:发起几次请求就可以了。
-
微服务实例与
Sentinel Dashboard
间的网络不通。比如,一个在内网,另一个在公网,或者由于防火墙原因导致二者不能正常通信。解决办法:保证网络畅通,都部署到内网或都部署到公网,抑或使用内网穿透技术。 -
在使用
Docker
或Kubernetes
等容器化技术部署时导致的网络不通,和问题③类似。
网上有很多这个问题的解决办法,不过大部分都是关于上述 4 种情形的。笔者并未搜索到未配置 Sentinel
拦截器导致的页面空白问题,因此导致在错误的思路上花费了很多的时间。
本章主要讲解微服务架构项目中整合 Sentinel
的相关编码过程,对实战部分的讲解做补充和优化。之后对整合 Sentinel
时遇到的一个 “坑” 做了复盘,详细地记录了遇到问题后笔者的处理过程和思考过程,希望对读者有一些启发。