postgresql/Vacuum 中的大量 live/dead 元组无法正常工作
High number of live/dead tuples in postgresql/ Vacuum not working
有一个 table,它有 200 行。但是显示的活元组数量不止于此(大约 60K)。
select count(*) from subscriber_offset_manager;
count
-------
200
(1 row)
SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
schemaname | relname | n_live_tup | n_dead_tup
------------+---------------------------+------------+------------
public | subscriber_offset_manager | 61453 | 5
(1 row)
但是从 pg_stat_activity 和 pg_locks 可以看出,我们无法跟踪任何打开的连接。
SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity
USING (pid)
WHERE relation::regclass = 'subscriber_offset_manager'::regclass
;
query | state | locktype | mode
-------+-------+----------+------
(0 rows)
我也在这个 table 上尝试了全真空,结果如下:
- 始终没有删除任何行
- 有时所有活的元组都会变成死元组。
这是输出。
vacuum FULL VERBOSE ANALYZE subscriber_offset_manager;
INFO: vacuuming "public.subscriber_offset_manager"
INFO: "subscriber_offset_manager": found 0 removable, 67920 nonremovable row versions in 714 pages
DETAIL: 67720 dead row versions cannot be removed yet.
CPU 0.01s/0.06u sec elapsed 0.13 sec.
INFO: analyzing "public.subscriber_offset_manager"
INFO: "subscriber_offset_manager": scanned 710 of 710 pages, containing 200 live rows and 67720 dead rows; 200 rows in sample, 200 estimated total rows
VACUUM
SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
schemaname | relname | n_live_tup | n_dead_tup
------------+---------------------------+------------+------------
public | subscriber_offset_manager | 200 | 67749
10 秒后
SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
schemaname | relname | n_live_tup | n_dead_tup
------------+---------------------------+------------+------------
public | subscriber_offset_manager | 68325 | 132
我们的应用如何查询此 table .
我们的应用程序一般select一些行并根据一些业务计算,更新行。
select query -- select based on some id
select * 来自 subscriber_offset_manager 其中 shard_id=1 ;
更新查询 -- 为这个 selected 分片 id
更新一些其他列
大约 20 个线程并行执行此操作,一个线程仅处理一行。
- app 是在 java 中编写的,我们正在使用 hibernate 进行数据库操作。
- Postgresql 版本为 9.3.24
另一个有趣的观察:
- 当我停止我的 java 应用程序然后进行完全真空处理时,它工作正常(行数和活动元组数变得相等)。因此,如果我们 select 并从 java app 不断更新,就会出现问题。 –
Problem/Issue
这些活元组有时会变成死元组,有时又会活过来。
由于 table 的上述行为 select 需要时间并增加服务器上的负载,因为那里有很多 live/deadtuples ..
毕竟可能会有锁,您的查询可能会产生误导:
SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity USING (pid)
WHERE relation = 'subscriber_offset_manager'::regclass
pg_locks.pid
可以为 NULL,则连接将消除行。 The manual for Postgres 9.3:
Process ID of the server process holding or awaiting this lock, or null if the lock is held by a prepared transaction
大胆强调我的。 (在第 10 页中仍然相同。)
您对简单查询有什么了解吗?
SELECT * FROM pg_locks
WHERE relation = 'subscriber_offset_manager'::regclass;
这可以解释为什么 VACUUM
抱怨:
DETAIL: 67720 dead row versions cannot be removed yet.
反过来,这会指出您的应用程序逻辑/查询中存在问题,锁定了不必要的行数。
我的第一个想法是 long 运行 transactions,其中即使是简单的 SELECT
(获取低级 ACCESS SHARE
锁)也可以阻塞VACUUM
从完成它的工作。 20 个并行线程可能会无限期地链接起来并锁定 VACUUM
。使您的交易(及其锁定)尽可能简短。并确保您的查询得到优化,并且不要锁定不必要的行。
还有一点需要注意:transaction isolation 级 SERIALIZABLE
或 REPEATABLE READ
使 VACUUM
更难清理。默认 READ COMMITTED
模式的限制较少,但 VACUUM
仍然可以像讨论的那样被阻止。
相关:
我知道阻碍 VACUUM
工作的三件事:
长运行笔交易。
未提交的准备事务。
过时的复制槽。
详情见my blog post。
我找到问题了☺。
为了理解这个问题,请考虑以下流程:
线程 1 -
- 打开休眠会话
- 对 Table-A 进行一些查询
- Select 来自 subscriber_offset_manager
- 更新subscriber_offset_manager。
- 关闭会话。
Thread-1运行类型的许多线程并行。
线程 2 -
- 这些类型的线程 运行 是并行的。
- 打开休眠会话
- 在 Table-A
上进行一些 select 查询
- 不关闭会话。(会话泄漏。)
临时解决方案 - 如果我使用 pg_cancel_backend 关闭所有由 Thread-2 建立的连接,则吸尘开始工作。
此外,我们已多次重现该问题,并尝试了此解决方案并且有效。
现在有以下疑惑还没有解答。
- 为什么 postgres 没有显示与 table "subscriber_offset_manager" 相关的任何数据。
- 如果我们 运行 select 在 Table-A ,使用 psql 。
- 为什么 postgres 与 jdbc 这样工作。
一些更令人兴奋的观察:
- 事件如果我们运行在不同的会话中查询“subscriber_offset_manager”然后也会发出问题;
- 我们在这里发现许多实例,其中线程 2 正在处理第三个 table“Table-C”,问题即将出现
- pg_stat_activity 中所有这些类型的 od 交易状态是“idle_in_transaction。”
@Erwin Brandstetter 和@Laurenz Albe,如果您知道存在与 postgres/jdbc 相关的错误。
有一个 table,它有 200 行。但是显示的活元组数量不止于此(大约 60K)。
select count(*) from subscriber_offset_manager;
count
-------
200
(1 row)
SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
schemaname | relname | n_live_tup | n_dead_tup
------------+---------------------------+------------+------------
public | subscriber_offset_manager | 61453 | 5
(1 row)
但是从 pg_stat_activity 和 pg_locks 可以看出,我们无法跟踪任何打开的连接。
SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity
USING (pid)
WHERE relation::regclass = 'subscriber_offset_manager'::regclass
;
query | state | locktype | mode
-------+-------+----------+------
(0 rows)
我也在这个 table 上尝试了全真空,结果如下:
- 始终没有删除任何行
- 有时所有活的元组都会变成死元组。
这是输出。
vacuum FULL VERBOSE ANALYZE subscriber_offset_manager;
INFO: vacuuming "public.subscriber_offset_manager"
INFO: "subscriber_offset_manager": found 0 removable, 67920 nonremovable row versions in 714 pages
DETAIL: 67720 dead row versions cannot be removed yet.
CPU 0.01s/0.06u sec elapsed 0.13 sec.
INFO: analyzing "public.subscriber_offset_manager"
INFO: "subscriber_offset_manager": scanned 710 of 710 pages, containing 200 live rows and 67720 dead rows; 200 rows in sample, 200 estimated total rows
VACUUM
SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
schemaname | relname | n_live_tup | n_dead_tup
------------+---------------------------+------------+------------
public | subscriber_offset_manager | 200 | 67749
10 秒后
SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
schemaname | relname | n_live_tup | n_dead_tup
------------+---------------------------+------------+------------
public | subscriber_offset_manager | 68325 | 132
我们的应用如何查询此 table .
我们的应用程序一般select一些行并根据一些业务计算,更新行。
select query -- select based on some id
select * 来自 subscriber_offset_manager 其中 shard_id=1 ;
更新查询 -- 为这个 selected 分片 id
更新一些其他列
大约 20 个线程并行执行此操作,一个线程仅处理一行。
- app 是在 java 中编写的,我们正在使用 hibernate 进行数据库操作。
- Postgresql 版本为 9.3.24
另一个有趣的观察: - 当我停止我的 java 应用程序然后进行完全真空处理时,它工作正常(行数和活动元组数变得相等)。因此,如果我们 select 并从 java app 不断更新,就会出现问题。 –
Problem/Issue
这些活元组有时会变成死元组,有时又会活过来。
由于 table 的上述行为 select 需要时间并增加服务器上的负载,因为那里有很多 live/deadtuples ..
毕竟可能会有锁,您的查询可能会产生误导:
SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity USING (pid)
WHERE relation = 'subscriber_offset_manager'::regclass
pg_locks.pid
可以为 NULL,则连接将消除行。 The manual for Postgres 9.3:
Process ID of the server process holding or awaiting this lock, or null if the lock is held by a prepared transaction
大胆强调我的。 (在第 10 页中仍然相同。)
您对简单查询有什么了解吗?
SELECT * FROM pg_locks
WHERE relation = 'subscriber_offset_manager'::regclass;
这可以解释为什么 VACUUM
抱怨:
DETAIL: 67720 dead row versions cannot be removed yet.
反过来,这会指出您的应用程序逻辑/查询中存在问题,锁定了不必要的行数。
我的第一个想法是 long 运行 transactions,其中即使是简单的 SELECT
(获取低级 ACCESS SHARE
锁)也可以阻塞VACUUM
从完成它的工作。 20 个并行线程可能会无限期地链接起来并锁定 VACUUM
。使您的交易(及其锁定)尽可能简短。并确保您的查询得到优化,并且不要锁定不必要的行。
还有一点需要注意:transaction isolation 级 SERIALIZABLE
或 REPEATABLE READ
使 VACUUM
更难清理。默认 READ COMMITTED
模式的限制较少,但 VACUUM
仍然可以像讨论的那样被阻止。
相关:
我知道阻碍 VACUUM
工作的三件事:
长运行笔交易。
未提交的准备事务。
过时的复制槽。
详情见my blog post。
我找到问题了☺。
为了理解这个问题,请考虑以下流程:
线程 1 -
- 打开休眠会话
- 对 Table-A 进行一些查询
- Select 来自 subscriber_offset_manager
- 更新subscriber_offset_manager。
- 关闭会话。
Thread-1运行类型的许多线程并行。
线程 2 -
- 这些类型的线程 运行 是并行的。
- 打开休眠会话
- 在 Table-A 上进行一些 select 查询
- 不关闭会话。(会话泄漏。)
临时解决方案 - 如果我使用 pg_cancel_backend 关闭所有由 Thread-2 建立的连接,则吸尘开始工作。
此外,我们已多次重现该问题,并尝试了此解决方案并且有效。
现在有以下疑惑还没有解答。
- 为什么 postgres 没有显示与 table "subscriber_offset_manager" 相关的任何数据。
- 如果我们 运行 select 在 Table-A ,使用 psql 。
- 为什么 postgres 与 jdbc 这样工作。
一些更令人兴奋的观察:
- 事件如果我们运行在不同的会话中查询“subscriber_offset_manager”然后也会发出问题;
- 我们在这里发现许多实例,其中线程 2 正在处理第三个 table“Table-C”,问题即将出现
- pg_stat_activity 中所有这些类型的 od 交易状态是“idle_in_transaction。”
@Erwin Brandstetter 和@Laurenz Albe,如果您知道存在与 postgres/jdbc 相关的错误。