[springboot] SpringBoot启动成功后因actuator健康检测报:Redis health check failed/RedisConnectionFailureException: Cannot get Jedis connection; Failed connecting to host localhost:6379

0 序

  • 背景:项目中引入了 spring-boot-starter-actuator 健康检测模块
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

1 问题描述

  • 确认微服务刚启动后,因K8S集群周期性定时(默认每隔10s)健康检查微服务,导致报如下错误:

...
[TID: N/A] [xxx-service] [system] [2024/03/11 16:08:53.610] [INFO ] [main] [XXXXServiceBizApplication] main:59__||__ server startup - end
[TID: Ignored_Trace] [xxx-service] [system] [2024/03/11 16:08:59.186] [INFO ] [http-nio-9527-exec-1] [DirectJDKLog] log:173__||__Initializing Spring DispatcherServlet 'dispatcherServlet'
[TID: Ignored_Trace] [xxxx-service] [system] [2024/03/11 16:08:59.679] [INFO ] [http-nio-9527-exec-1] [HikariDataSource] getConnection$original$aVZjWOBW:110__|N/A(xxxx-service)|__HikariPool-1 - Starting...
[TID: Ignored_Trace] [xxxx-service] [system] [2024/03/11 16:08:59.788] [INFO ] [http-nio-9527-exec-1] [HikariDataSource] getConnection$original$aVZjWOBW:123__|N/A(xxxx-service)|__HikariPool-1 - Start completed.
[TID: Ignored_Trace] [xxxx-service] [system] [2024/03/11 16:08:59.895] [WARN ] [http-nio-9527-exec-1] [AbstractHealthIndicator] health:87__|N/A(xxxx-service)|__Redis health check failed
org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Failed connecting to host localhost:6379
	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:282) ~[spring-data-redis-2.3.9.RELEASE.jar!/:2.3.9.RELEASE]
	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:476) ~[spring-data-redis-2.3.9.RELEASE.jar!/:2.3.9.RELEASE]
	at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:134) ~[spring-data-redis-2.3.9.RELEASE.jar!/:2.3.9.RELEASE]
	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:97) ~[spring-data-redis-2.3.9.RELEASE.jar!/:2.3.9.RELEASE]
	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:84) ~[spring-data-redis-2.3.9.RELEASE.jar!/:2.3.9.RELEASE]
	at org.springframework.boot.actuate.redis.RedisHealthIndicator.doHealthCheck(RedisHealthIndicator.java:51) ~[spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.AbstractHealthIndicator.health(AbstractHealthIndicator.java:82) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthIndicator.getHealth(HealthIndicator.java:37) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthEndpointWebExtension.getHealth(HealthEndpointWebExtension.java:85) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthEndpointWebExtension.getHealth(HealthEndpointWebExtension.java:44) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getContribution(HealthEndpointSupport.java:99) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getAggregateHealth(HealthEndpointSupport.java:110) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getContribution(HealthEndpointSupport.java:96) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getHealth(HealthEndpointSupport.java:74) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthEndpointSupport.getHealth(HealthEndpointSupport.java:61) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthEndpointWebExtension.health(HealthEndpointWebExtension.java:71) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.health.HealthEndpointWebExtension.health(HealthEndpointWebExtension.java:60) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_402]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_402]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_402]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_402]
	at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282) [spring-core-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]
	at org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker.invoke(ReflectiveOperationInvoker.java:77) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation.invoke(AbstractDiscoveredOperation.java:60) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$ServletWebOperationAdapter.handle(AbstractWebMvcEndpointHandlerMapping.java:305) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
	at org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(AbstractWebMvcEndpointHandlerMapping.java:388) [spring-boot-actuator-2.3.12.RELEASE.jar!/:2.3.12.RELEASE]
...

疑问:没有配置 localhost:6379 的redis数据源,哪来的 redis 连接信息呢?

  • 已检查确认:工程中没有配置任何关于 REDIS 的数据源
  • Spring Boot 版本 : 2.3.12.RELEASE

2 问题分析

通过spring-boot-actuator-autoconfigure:2.3.12.RELEASEjar包找到了源码:

2.1 RedisHealthContributorAutoConfiguration

  • org.springframework.boot.actuate.autoconfigure.redis.RedisHealthContributorAutoConfiguration
/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.actuate.autoconfigure.redis;

import java.util.Map;

import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.health.HealthContributor;
import org.springframework.boot.actuate.redis.RedisHealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;

/**
 * {@link EnableAutoConfiguration Auto-configuration} for {@link RedisHealthIndicator}.
 *
 * @author Christian Dupuis
 * @author Richard Santana
 * @author Stephane Nicoll
 * @author Mark Paluch
 * @since 2.1.0
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisConnectionFactory.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnEnabledHealthIndicator("redis") // 关键代码 : management.health.redis
@AutoConfigureAfter({ RedisAutoConfiguration.class, RedisReactiveHealthContributorAutoConfiguration.class })
public class RedisHealthContributorAutoConfiguration
		extends CompositeHealthContributorConfiguration<RedisHealthIndicator, RedisConnectionFactory> {

	@Bean
	@ConditionalOnMissingBean(name = { "redisHealthIndicator", "redisHealthContributor" })//关键代码
	public HealthContributor redisHealthContributor(Map<String, RedisConnectionFactory> redisConnectionFactories) {
		return createContributor(redisConnectionFactories);
	}

}

2.2 ConditionalOnEnabledHealthIndicator

  • org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator
/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.actuate.autoconfigure.health;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.context.annotation.Conditional;

/**
 * {@link Conditional @Conditional} that checks whether or not a default health indicator
 * is enabled. Matches if the value of the {@code management.health.<name>.enabled}
 * property is {@code true}. Otherwise, matches if the value of the
 * {@code management.health.defaults.enabled} property is {@code true} or if it is not
 * configured.
 *
 * @author Stephane Nicoll
 * @since 2.0.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnEnabledHealthIndicatorCondition.class) //依赖: OnEnabledHealthIndicatorCondition
public @interface ConditionalOnEnabledHealthIndicator {

	/**
	 * The name of the health indicator.
	 * @return the name of the health indicator
	 */
	String value();

}

2.3 OnEnabledHealthIndicatorCondition

  • org.springframework.boot.actuate.autoconfigure.health.OnEnabledHealthIndicatorCondition
/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.actuate.autoconfigure.health;

import org.springframework.boot.actuate.autoconfigure.OnEndpointElementCondition;
import org.springframework.context.annotation.Condition;

/**
 * {@link Condition} that checks if a health indicator is enabled.
 *
 * @author Stephane Nicoll
 */
class OnEnabledHealthIndicatorCondition extends OnEndpointElementCondition {

	OnEnabledHealthIndicatorCondition() {
		super("management.health.", ConditionalOnEnabledHealthIndicator.class);//配置前缀: management.health.
	}

}

3 解决方法

方法1:在配置文件中禁用redis健康检查

通过@ConditionalOnEnabledHealthIndicator可以知道解决办法,在配置文件中禁用redis检查。 【本方法,亲测有效】

management:
  health:
    # reference-doc
    # https://www.cnblogs.com/yl97/p/14926029.html
    # {@link org.springframework.boot.actuate.autoconfigure.health.OnEnabledHealthIndicatorCondition }
    # org.springframework.boot.actuate.autoconfigure.redis.RedisHealthContributorAutoConfiguration
    redis: # false : 禁用 redis 检查
      enabled: false 

方法2:自定义配置Class/Bean("RedisHealthIndicator")

查看源码发现RedisHealthIndicator继承AbstractHealthIndicatorAbstractHealthIndicator实现了HealthIndicator接口。即:我们可通过自定义配置来解决。

@Configuration
public class RedisHealthIndicator implements HealthIndicator{

    @Override
    public Health health() {
        return Health.up().build();
    }
}

特别注意:必须要将原有的RedisHealthIndicator类覆盖,所以class名为RedisHealthIndicator。如果类想另起名则需指定bean名为redisHealthIndicator,否则,(有网友反馈)还是会出现错误信息。

X 参考文献

posted @ 2024-03-11 16:49  千千寰宇  阅读(197)  评论(0编辑  收藏  举报