首页 > 解决方案 > Actix Rust deadpool_postgres:未释放数据库连接

问题描述

我有一个连接到 Postgres 数据库的 Actix-web 服务器。

我注意到在 1000 次请求后,我的 Postgres DB 的 RAM 使用率飙升

当我停止 actix-web 时,db 持有的 RAM 被清除。这让我相信我的代码没有释放连接。

我找不到实际释放连接的示例。看起来它是在其他人的代码中推断出来的。

这是我的:

async fn hellow_world(a : f32, b : f32, pool: &Pool) -> Result<Value, PoolError> {
    let client: Client = pool.get().await?;
    let sql = format!("select \"json\" from public.table_a WHERE a={} and b={}", a, b);
    let stmt = client.prepare(&sql).await?;
    let row = client.query_one(&stmt, &[]).await?;
    let result : Value = row.get(0);
    Ok(result)
}

#[derive(Deserialize)]
pub struct MyRequest {
   a: f32,
   b: f32
}

#[get("/hello")]
async fn sv_hellow_world(info: web::Query<MyRequest>, db_pool: web::Data<Pool>) -> Result<HttpResponse, Error> {
    let response : Value = hellow_world(info.a, info.b, &db_pool).await?;
    Ok(HttpResponse::Ok().json(response))
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    dotenv().ok();
    let config = Config::from_env().unwrap();
    let pool = config.pg.create_pool(tokio_postgres::NoTls).unwrap();

    env_logger::from_env(Env::default().default_filter_or("info")).init();

    let server = HttpServer::new(move || App::new().wrap(Logger::default()).wrap(Logger::new("%a %{User-Agent}i")).data(pool.clone()).service(sv_hellow_world))
        .bind("0.0.0.0:3000")?
        .run();
    server.await
}

标签: postgresqlrustrust-actixactix-web

解决方案


根据进一步的测试,@Werner 确定代码堆积了服务器端准备好的语句。

目前尚不清楚这些语句是否可以使用此库关闭。

可以使用两种方法中的任何一种来避免此问题:

  1. 使用单个共享的预处理语句
  2. 使用直接查询表单而不是准备好的语句

我原则上推荐第一种方法,因为它更有效并且可以防止 SQL 注入。它应该看起来像这样:

async fn hellow_world(a : f32, b : f32, pool: &Pool) -> Result<Value, PoolError> {
    let client: Client = pool.get().await?;
    let stmt = client.prepare("select \"json\" from public.table_a WHERE a=$1::numeric and b=$2::numeric").await?;
    let row = client.query_one(&stmt, &[&a, &b]).await?;
    let result : Value = row.get(0);
    Ok(result)
}

使用此代码,应在池的每个连接上只创建一个准备好的语句。


推荐阅读