Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 当pgbouncer具有pool_mode=transaction时,如果运行单个查询,最坏的情况是什么?_Performance_Pgbouncer - Fatal编程技术网

Performance 当pgbouncer具有pool_mode=transaction时,如果运行单个查询,最坏的情况是什么?

Performance 当pgbouncer具有pool_mode=transaction时,如果运行单个查询,最坏的情况是什么?,performance,pgbouncer,Performance,Pgbouncer,让我们假设pgbouncer的以下配置: 如果我有这样的联系 begin transaction ... commit transaction 这非常简单,因为在事务打开期间,pgbouncer将仅为该客户端连接保留后端连接 但是,如果客户端应用程序改为发送 select select pg_advisory_lock(123); begin transaction isolation level serializable ... commit transaction select selec

让我们假设pgbouncer的以下配置:

如果我有这样的联系

begin transaction
...
commit transaction
这非常简单,因为在事务打开期间,pgbouncer将仅为该客户端连接保留后端连接

但是,如果客户端应用程序改为发送

select select pg_advisory_lock(123);
begin transaction isolation level serializable
...
commit transaction
select select pg_advisory_unlock(123);
后端连接是否可能在查询之间切换,以便后端连接1获得锁,连接2执行事务,连接3尝试解锁建议锁,但显然失败了

建议锁定可用于高负载情况下的优化,其中序列化事务之间的冲突会由于大量回滚事务而导致后端数据库服务器上的高CPU负载。通常情况下,冲突很少发生,因此与使用显式锁定相比,可序列化事务的延迟更低

以下是我能找到的唯一相关问题:
–但这并不能解决我的问题。阅读答案表明,如果在上次查询后未超过超时的情况下获取/释放咨询锁,上述功能应该可以正常工作,但我不知道这是否可信。

我使用以下pgbouncer配置对此进行了测试:

[pgbouncer]
pool_mode = transaction
server_reset_query = DISCARD ALL
server_check_query = select 1
server_reset_query_always = 0

max_client_conn = 2000
default_pool_size = 1
min_pool_size = 1

reserve_pool_size = 0
reserve_pool_timeout = 5

max_db_connections = 1
以及通过pgbouncer到同一数据库的两个并行连接。下面使用p1jap2作为每个进程发送的查询的标识符。如果进行以下简单测试:

P1: set application_name=p1;
P1: select pg_advisory_lock(42);
P2: set application_name=p2;
P1: show application_name;
    p1
P2: select pg_advisory_lock(42);
P2. show application_name;
    p2
。。。似乎两个连接都能够获得相同的独占建议锁,即使它们具有唯一的应用程序名称值,因此每个连接都应该是唯一的!事实上,所有命令都是使用单个连接发送到postgres的,因此该单个连接已经获得了建议锁42两次,并且如果以后每个P1和P2连接两次逻辑地释放相同的锁一次,则一切正常。发生这种情况的原因是,独占锁可以由同一所有者多次使用,并且必须在任何其他进程获取相同的锁之前释放相同的次数

因此,也可能出现以下情况:

P1: select pg_advisory_lock(42);
P2: select pg_advisory_lock(42);
P1: begin transaction isolation level serializable;
P1: select 1;
P1: commit;
P2: begin transaction isolation level serializable;
P2: select 1;
P2: commit;
P1: select pg_advisory_unlock(42);
P2: select pg_advisory_unlock(42);
想象多个查询和数据库更改,而不是上面的选择1

请注意,这两个数据库客户端应用程序在执行可序列化事务之前都获得了独占锁,但仍然无法正常工作

显然,这种情况是不可能的,除非P1和P2实际上共享同一个数据库连接。通常情况下,通过pgbouncer会允许多个并行数据库连接,所以这种代码是快速的。在实践中,它将一直工作,直到您达到高服务器负载,然后您会随机失败,这取决于哪个查询与来自另一个客户机的另一个查询一起执行

因此,如果pool_mode=transaction处于活动状态,则在事务之外执行任何查询肯定是不安全的。选项server\u reset\u query\u always=1无法真正解决问题,因此不应使用该选项。如果您觉得需要服务器\u重置\u查询\u始终=1,则需要改用pool\u mode=session,否则可能会导致随机数据损坏

此外,pgbouncer似乎足够聪明,可以伪造一些特定于连接的数据。例如,当P1在上面的第一个示例中设置其应用程序名称,然后在P2已在同一连接上设置其应用程序名称后查询它时,P1将获得预期结果。但是,如果在pg_stat_活动发生时监视该活动,则每次P1或P2发送查询时,到postgres的唯一活动连接都会更改其应用程序名称值。这使得这种混合在pool_mode=transaction中似乎没有问题

最后,在事务之外设置应用程序名称应该是安全的,但在postgres级别上实际实现的任何功能都是不安全的。除非您完全确定pgbouncer可以模拟您需要的功能,否则不要在pool_mode=transaction中向从pgbouncer获取的数据库连接发出任何查询,除了begin…、commit。。。或者回滚。一旦事务处于活动状态,就为您保留了连接,在您提交或回滚之前,一切都与真正的直接连接postgres一样工作

我真的希望,如果设置了pool_mode=transaction,那么当客户机试图在事务之外执行任何查询时,pgbouncer总是会返回一个错误。不幸的是,这不是我们生活的现实,pgbouncer客户必须小心

P1: select pg_advisory_lock(42);
P2: select pg_advisory_lock(42);
P1: begin transaction isolation level serializable;
P1: select 1;
P1: commit;
P2: begin transaction isolation level serializable;
P2: select 1;
P2: commit;
P1: select pg_advisory_unlock(42);
P2: select pg_advisory_unlock(42);