Actix Rust deadpool_postgres:未释放数据库连接
Actix Rust deadpool_postgres: DB connections not released
我有一个连接到 Postgres 数据库的 Actix-web 服务器。
我注意到 在 1000 次请求后,我的 Postgres 数据库的 RAM 使用率飙升。
当我停止 actix-web 时,数据库占用的 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
}
根据进一步的测试,@Werner 确定代码正在堆积服务器端准备好的语句。
尚不清楚是否可以使用此库关闭这些语句。
可以使用以下两种方法之一来避免此问题:
- 使用一个共享的预处理语句
- 使用直接查询形式代替准备语句
我原则上推荐第一种方法,因为它更有效并且可以防止 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=::numeric and b=::numeric").await?;
let row = client.query_one(&stmt, &[&a, &b]).await?;
let result : Value = row.get(0);
Ok(result)
}
使用此代码,只应在池的每个连接上创建一个准备好的语句。
我有一个连接到 Postgres 数据库的 Actix-web 服务器。
我注意到 在 1000 次请求后,我的 Postgres 数据库的 RAM 使用率飙升。
当我停止 actix-web 时,数据库占用的 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
}
根据进一步的测试,@Werner 确定代码正在堆积服务器端准备好的语句。
尚不清楚是否可以使用此库关闭这些语句。
可以使用以下两种方法之一来避免此问题:
- 使用一个共享的预处理语句
- 使用直接查询形式代替准备语句
我原则上推荐第一种方法,因为它更有效并且可以防止 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=::numeric and b=::numeric").await?;
let row = client.query_one(&stmt, &[&a, &b]).await?;
let result : Value = row.get(0);
Ok(result)
}
使用此代码,只应在池的每个连接上创建一个准备好的语句。