開發中使用Consul作為服務註冊中心時,專案接入sharding-jdbc後,db測活一致失敗問題解決
阿新 • • 發佈:2018-12-14
一、問題背景:
專案中(Spring boot)使用consul作為服務註冊中心時,當接入sharding-jdbc 1.4.x版本後,健康檢查一直失敗。主要是db檢測失敗,丟擲以下錯誤:
"db": { "status": "DOWN", "database": "MySQL", "error": "java.lang.NullPointerException: null" }
二、問題分析:
1.Consul中的測活依賴於spring-boot-starter-actuator包,不新增會check failing;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
2.在actuator包中下面HealthIndicators會被Spring Boot自動配置:
名字 | 描述 |
---|---|
CassandraHealthIndicator | 檢查Cassandra database是否正常 |
DiskSpaceHealthIndicator | 低磁碟空間檢測 |
DataSourceHealthIndicator | 檢查資料庫連線是否正常 |
ElasticsearchHealthIndicator | 檢查Elasticsearch cluster是否正常 |
JmsHealthIndicator | 檢查JMS broker是否正常 |
MailHealthIndicator | 檢查mail server是否正常 |
MongoHealthIndicator | 檢查Mongo database是否正常 |
RabbitHealthIndicator | 檢查Rabbit server是否正常 |
RedisHealthIndicator | 檢查Redis server是否正常 |
SolrHealthIndicator | 檢查Solr server是否正常 |
3.該問題主要是在執行DataSourceHealthIndicator時,報錯。
dbHealthIndicator自動註冊的原始碼部分:
//org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration 類中定義 //.... @Bean @ConditionalOnMissingBean(name = "dbHealthIndicator") public HealthIndicator dbHealthIndicator() { return createHealthIndicator(this.dataSources); } @Override protected DataSourceHealthIndicator createHealthIndicator(DataSource source) { return new DataSourceHealthIndicator(source, getValidationQuery(source)); } private String getValidationQuery(DataSource source) { DataSourcePoolMetadata poolMetadata = this.poolMetadataProvider .getDataSourcePoolMetadata(source); return (poolMetadata == null ? null : poolMetadata.getValidationQuery()); }
DataSourceHealthIndicator的資料庫檢測部分原始碼:
//類
//org.springframework.boot.actuate.health.DataSourceHealthIndicator
//...
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
if (this.dataSource == null) {
builder.up().withDetail("database", "unknown");
}
else {
doDataSourceHealthCheck(builder);
}
}
private void doDataSourceHealthCheck(Health.Builder builder) throws Exception {
String product = getProduct();
builder.up().withDetail("database", product);
String validationQuery = getValidationQuery(product);
if (StringUtils.hasText(validationQuery)) {
try {
// Avoid calling getObject as it breaks MySQL on Java 7
List<Object> results = this.jdbcTemplate.query(validationQuery,
new SingleColumnRowMapper());
Object result = DataAccessUtils.requiredSingleResult(results);
builder.withDetail("hello", result);
}
catch (Exception ex) {
builder.down(ex);
}
}
}
//...
資料庫檢測時,主要是語句:
List<Object> results = this.jdbcTemplate.query(validationQuery, new SingleColumnRowMapper());
執行時報錯,其中validationQuery=“SELECT 1” 。
問題可能原因是:sharding-jdbc 對於validationQuery=“SELECT 1”的語句不支援。(暫時未在官方文件上找到相關說明,後續進行驗證)
三、解決方法:
1.利用Spring中同名Bean相互覆蓋的特性,自定義HealthIndicators類 DbHealthIndicator 來替換掉原來的db檢測bean:
@Component
public class DbHealthIndicator implements HealthIndicator {
@Override
public Health health() {
int errorCode = check();
if (errorCode != 0) {
return Health.down().withDetail("Error Code", errorCode) .build();
}
return Health.up().build();
}
int check(){
//可以實現自定義的資料庫檢測邏輯
return 0;
}
}