13.4场景3 数据库连接池耗尽

分类: 故障排查 Troubleshooting 实战

场景 3:数据库连接池耗尽

欢迎回到第 13 章的学习。在上一节,我们学习了错误率突然上升的排查方法。现在我们要学习场景 3:数据库连接池耗尽。

本节将学习:Metrics 显示连接池饱和、查看数据库 Traces、分析连接使用模式、定位连接泄露、以及优化连接池配置。

Metrics 显示连接池饱和

Metrics 显示连接池饱和的作用是什么? 通过 Metrics 发现连接池问题,确认问题的严重程度。

如何查看连接池 Metrics? 查看以下指标:

  • 连接池使用率
  • 活跃连接数
  • 等待连接数
  • 连接获取时间

异常指标示例:

  • 连接池使用率达到 100%
  • 等待连接数持续增加
  • 连接获取时间超过 30 秒

连接池 Metrics 查询:

# 连接池使用率
hikari_connections_active / hikari_connections_total

# 等待连接数
hikari_connections_pending

# 连接获取时间
avg(hikari_connections_acquire_nanos) / 1000000

查看数据库 Traces

查看数据库 Traces 的作用是什么? 使用 Trace 查看数据库连接的使用情况,了解连接获取和释放的模式。

如何查看数据库 Traces? 在 Grafana Tempo 中查询数据库相关的 Trace,关注连接获取和释放的 Span。

TraceQL 查询示例:

# Queries related to database connections Trace
{db.system="mysql"} && {db.operation="SELECT"}

# The one that takes a long time to obtain a query connection Trace
{db.system="mysql"} && {duration > 5s}

分析连接使用模式

分析连接使用模式的作用是什么? 分析连接的使用模式,识别连接使用异常。

如何分析连接使用模式? 分析以下模式:

  • 连接获取频率
  • 连接使用时长
  • 连接归还情况
  • 连接等待模式

异常模式示例:

  • 连接使用时间过长(> 5 分钟)
  • 连接未及时归还
  • 连接获取频率异常高

连接使用模式分析:

# 连接使用时长分布
histogram_quantile(0.95, db_connection_duration_seconds_bucket)

# 连接获取频率
sum(rate(db_connections_acquired_total[5m]))

# 连接归还频率
sum(rate(db_connections_released_total[5m]))

定位连接泄露

定位连接泄露的作用是什么? 识别未归还的连接,找到连接泄露的源头。

如何定位连接泄露? 分析连接获取和归还的时间差,识别长时间未归还的连接。

连接泄露特征:

  • 连接获取后长时间未归还
  • 连接使用时间超过正常范围
  • 连接数量持续增长

连接泄露检测:

// Connection leak detection code example
@Component
public class ConnectionLeakDetector {
    private final Map<Connection, Long> connectionAcquireTime = new ConcurrentHashMap<>();
    
    public void onConnectionAcquired(Connection connection) {
        connectionAcquireTime.put(connection, System.currentTimeMillis());
    }
    
    public void onConnectionReturned(Connection connection) {
        connectionAcquireTime.remove(connection);
    }
    
    @Scheduled(fixedRate = 60000)
    public void detectLeaks() {
        long now = System.currentTimeMillis();
        long leakThreshold = 300000; // 5minutes
        
        connectionAcquireTime.forEach((conn, acquireTime) -> {
            long usageTime = now - acquireTime;
            if (usageTime > leakThreshold) {
                log.warn("Potential connection leak: {}ms", usageTime);
            }
        });
    }
}

优化连接池配置

优化连接池配置的作用是什么? 根据分析结果,优化连接池配置,解决连接池问题。

优化方案包括哪些呢?

第一个:增加连接池大小。 根据实际负载增加连接池大小。

第二个:优化连接超时。 设置合理的连接超时时间。

第三个:修复连接泄露。 修复代码中的连接泄露问题。

第四个:优化连接使用。 优化连接的使用模式,减少连接持有时间。

连接池配置优化:

# application.properties
# Increase the size of the connection pool
spring.datasource.hikari.maximum-pool-size=50
spring.datasource.hikari.minimum-idle=10

# Optimizing connection timeouts
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000

# Connection verification
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.validation-timeout=3000

本节小结

在本节中,我们学习了场景 3:数据库连接池耗尽:

第一个是 Metrics 显示连接池饱和。 通过 Metrics 发现连接池问题,确认问题的严重程度。

第二个是查看数据库 Traces。 使用 Trace 查看数据库连接的使用情况,了解连接获取和释放的模式。

第三个是分析连接使用模式。 分析连接的使用模式,识别连接使用异常。

第四个是定位连接泄露。 识别未归还的连接,找到连接泄露的源头。

第五个是优化连接池配置。 根据分析结果,优化连接池配置,解决连接池问题。

故障排查流程: Metrics 显示连接池饱和 → 查看数据库 Traces → 分析连接使用模式 → 定位连接泄露 → 优化连接池配置 → 验证修复效果。

这就是场景 3:数据库连接池耗尽。通过场景 3 的学习,我们掌握了数据库连接池耗尽的排查方法。

在下一节,我们将学习场景 4:前端性能问题。学习如何排查前端性能问题。