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

Vertx SqlClient内存泄漏求助:内存瓶颈从业务队列转移至客户端

问题:Vertx PostgreSQL Client 内存占用过高问题

我开发了一款应用,从非阻塞队列中获取独立SQL查询并在PostgreSQL数据库中执行。此前因插入处理瓶颈导致查询队列过大,引发内存问题。为提升出队速度,我尝试使用Vertx PostgreSQL Client,其出队效率确实大幅提升,但内存问题似乎从业务队列转移到了客户端侧(MAT分析显示内存异常)。我的代码实现如下:

@Override
public void initialize() {
    conOptions = new PgConnectOptions().setHost(conf.getDbHost()).setDatabase(conf.getDbName())
            .setUser(conf.getDbUser()).setPassword(conf.getDbPassword());

    poolOptions = new PoolOptions().setMaxSize(5);
    client = PgPool.client(conOptions, poolOptions);
}

@Override
public void executeUpdate(String sql) throws SQLException {
    countIn.accumulate(1L);
    client.query(sql).execute().onComplete(ar -> {
        countOut.accumulate(1L);
        if (!ar.succeeded()) {
            LogManager.getLogger(this.getClass()).error(ar.cause().getMessage());
        }
    });
}

请问我是否存在使用错误,或是Vertx或JDBC驱动存在遗漏配置?还是我的预期过于不切实际?


分析与解决方案

1. 核心问题定位

你当前的代码存在请求无限制提交的问题:

  • 业务队列的查询被快速取出后直接提交给Vertx客户端,但数据库连接池仅配置了5个连接(setMaxSize(5))
  • 当请求量远大于连接池处理能力时,Vertx会在客户端侧缓存待执行请求,最终导致内存堆积——这就是内存问题从业务队列转移到客户端的本质原因

2. 代码使用错误点

  • 未限制提交给客户端的请求并发量,相当于把业务队列的压力直接转嫁到了Vertx客户端的内部队列中
  • 未配置客户端请求等待队列的大小限制,默认情况下Vertx会无限制接收请求,直到内存耗尽

3. 优化配置与代码调整

(1)限制客户端请求队列大小

修改PoolOptions,添加等待队列上限,避免无限制内存堆积:

poolOptions = new PoolOptions()
        .setMaxSize(5) // 连接池最大连接数
        .setMaxWaitQueueSize(1000); // 等待队列的最大请求数,超过后新请求会直接失败

当队列满时,可根据业务需求选择:

  • 直接拒绝请求并记录日志,让上游队列自行做限流处理
  • 阻塞等待(不推荐,会回到之前的瓶颈问题)

(2)添加上游请求限流

在从业务队列取请求的环节做限流,确保提交给客户端的请求数不超过连接池+等待队列的承载能力,比如用Semaphore控制:

// 初始化时创建信号量,大小等于连接池+等待队列的总容量
private final Semaphore semaphore = new Semaphore(5 + 1000);

@Override
public void executeUpdate(String sql) throws SQLException {
    // 尝试获取许可,获取不到则拒绝请求
    if (!semaphore.tryAcquire()) {
        LogManager.getLogger(this.getClass()).warn("客户端请求队列已满,拒绝新SQL请求");
        return;
    }
    countIn.accumulate(1L);
    client.query(sql).execute().onComplete(ar -> {
        try {
            countOut.accumulate(1L);
            if (!ar.succeeded()) {
                LogManager.getLogger(this.getClass()).error(ar.cause().getMessage());
            }
        } finally {
            // 执行完成后释放许可,允许新请求提交
            semaphore.release();
        }
    });
}

(3)其他优化建议

  • 批量执行相似SQL:如果是大量重复的插入/更新语句,改用PreparedStatement批量提交,减少连接开销
  • 合理调整连接池大小:根据数据库的max_connections配置,适当增大setMaxSize,但不要超过数据库承载上限
  • 启用Vertx指标监控:通过Vertx的Metrics功能监控连接池使用率、等待队列长度,便于实时排查问题

4. 预期合理性

你的预期(提升出队速度同时解决内存问题)是完全合理的,但需要正确控制请求流,避免把压力从一个队列转移到另一个队列。Vertx客户端本身是高效的,但无限制的请求提交必然会引发内存问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:55:35