You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决OpenTelemetry Agent数据库连接指标重复值告警?

解决OpenTelemetry Agent 2.5.0中HikariCP连接池db.client.connections.idle.min重复指标告警问题

问题原因

该告警源于OpenTelemetry的HikariCP instrumentation在收集db.client.connections.idle.min异步指标时,同一个pool.name关联了多个HikariDataSource实例,导致每秒指标上报时同一属性集下出现多条记录,触发SDK的重复值校验告警。

从你的代码来看,db2DataSource()和postgresDataSource()每次调用都会创建新的HikariDataSource实例(例如db2DataSource()直接返回HikariDataSource(db2HikariConfig())),而所有实例的pool.name是固定值(基于naisAppName生成),这就造成了同一连接池名称对应多个数据源实例的情况。

解决方案(保留监控的前提下)

1. 确保连接池实例单例化

修改数据库配置代码,让每个连接池只创建一次实例,避免同一pool.name对应多个数据源:

object DatabaseConfig {
    // 单例初始化DB2数据源
    private val db2DataSource by lazy {
        HikariDataSource(db2HikariConfig())
    }

    // 单例初始化默认角色的PostgreSQL数据源
    private val defaultPostgresDataSource by lazy {
        postgresDataSource(postgresHikariConfig())
    }

    private fun db2HikariConfig(): HikariConfig {
        // 原代码逻辑保持不变
        val db2Properties: PropertiesConfig.Db2Properties = PropertiesConfig.Db2Properties()
        return HikariConfig().apply {
            maximumPoolSize = 10
            minimumIdle = 1
            poolName = "HikariPool-${PropertiesConfig.Configuration().naisAppName}-DB2"
            connectionTestQuery = "select 1 from sysibm.sysdummy1"
            dataSource =
                DB2SimpleDataSource().apply {
                    driverType = 4
                    enableNamedParameterMarkers = DB2BaseDataSource.YES
                    databaseName = db2Properties.name
                    serverName = db2Properties.host
                    portNumber = db2Properties.port.toInt()
                    currentSchema = db2Properties.schema
                    connectionTimeout = 1000
                    commandTimeout = 10000
                    user = db2Properties.username
                    setPassword(db2Properties.password)
                }
        }
    }

    private fun postgresHikariConfig(): HikariConfig {
        // 原代码逻辑保持不变
        val postgresProperties: PropertiesConfig.PostgresProperties = PropertiesConfig.PostgresProperties()
        return HikariConfig().apply {
            poolName = "HikariPool-${PropertiesConfig.Configuration().naisAppName}-POSTGRES"
            maximumPoolSize = 5
            minimumIdle = 1
            dataSource =
                PGSimpleDataSource().apply {
                    if (PropertiesConfig.isLocal()) {
                        user = postgresProperties.adminUsername
                        password = postgresProperties.adminPassword
                    }
                    serverNames = arrayOf(postgresProperties.host)
                    databaseName = postgresProperties.databaseName
                    portNumbers = intArrayOf(postgresProperties.port.toInt())
                    connectionTimeout = Duration.ofSeconds(10).toMillis()
                    maxLifetime = Duration.ofMinutes(30).toMillis()
                    initializationFailTimeout = Duration.ofMinutes(30).toMillis()
                }
        }
    }

    fun db2DataSource(): HikariDataSource = db2DataSource

    fun postgresDataSource(
        hikariConfig: HikariConfig = postgresHikariConfig(),
        role: String = PropertiesConfig.PostgresProperties().user,
    ): HikariDataSource {
        return when {
            PropertiesConfig.isLocal() -> HikariDataSource(hikariConfig)
            else ->
                HikariCPVaultUtil.createHikariDataSourceWithVaultIntegration(
                    hikariConfig,
                    PropertiesConfig.PostgresProperties().vaultMountPath,
                    role,
                )
        }
    }

    // 对外提供默认单例的PostgreSQL数据源
    fun defaultPostgresDataSource(): HikariDataSource = defaultPostgresDataSource

    fun postgresMigrate(dataSource: HikariDataSource = defaultPostgresDataSource()) {
        // 原代码逻辑保持不变
        Flyway.configure()
            .dataSource(dataSource)
            .initSql("""SET ROLE "${PropertiesConfig.PostgresProperties().adminUser}"""")
            .lockRetryCount(-1)
            .load()
            .migrate()
            .migrationsExecuted
        logger.info { "Migration finished" }
    }
}

通过lazy初始化保证每个连接池名称仅对应一个数据源实例,从根源上避免重复指标上报。

2. 升级OpenTelemetry Agent版本

OpenTelemetry Agent 2.5.0的HikariCP instrumentation存在已知的重复指标上报问题,升级到2.6.0及以上稳定版本,官方后续版本修复了异步指标的重复值处理逻辑。

3. 调整OTel指标聚合策略(临时 workaround)

如果无法立即升级或修改代码,可通过JVM参数配置,将db.client.connections.idle.min指标的聚合策略设置为last_value,让SDK忽略同一属性的重复值,仅保留最新记录:

-Dotel.sdk.metrics.export.aggregation.db.client.connections.idle.min=last_value

注:该配置在2.5.0版本中部分支持,更高版本的兼容性和稳定性更佳。

验证

修改后重启应用,观察日志是否不再出现目标WARN告警,同时通过OTel的metrics端点(如/metrics)确认db.client.connections.idle.min指标仍正常上报,且每个pool.name对应唯一的指标条目。

内容的提问来源于stack exchange,提问作者mudasar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:40:13