Ответ 1
Я знаю три вещи, которые заставляют VACUUM
выполнять свою работу:
-
Долгосрочные транзакции.
-
Подготовленные транзакции, которые не были совершены.
-
Слоты статической репликации.
См. Мое сообщение в блоге для подробностей.
Существует таблица, которая имеет 200 строк. Но количество живых кортежей, показывающих там больше, чем (около 60 тыс.).
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)
Я также попробовал полный вакуум на этой таблице, Ниже приведены результаты:
Вот вывод.
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
Как наш запрос приложения к этой таблице.
Наше приложение обычно выбирает некоторые строки и основывается на некоторых бизнес-расчетах, обновляет строку.
select query - выберите на основе некоторого id
выберите * from subscriber_offset_manager, где shard_id = 1;
update query - обновить другой столбец для этого выбранного идентификатора осколков
около 20 потоков выполняют это параллельно, а один поток работает только с одной строкой.
Еще одно интересное замечание: когда я останавливаю свое приложение java, а затем выполняю полный вакуум, он отлично работает (количество строк и живых кортежей становится равным). Таким образом, есть что-то неправильно, если мы постоянно выбираем и обновляем приложение java. -
Проблема/Выпуск
Эти живые кортежи несколько раз переходят к мертвым кортежам и через некоторое время снова оживают.
Из-за вышеуказанного поведения выберите из таблицы время и увеличив нагрузку на сервер, так как там есть много живых/мертвых точек.
Я знаю три вещи, которые заставляют VACUUM
выполнять свою работу:
Долгосрочные транзакции.
Подготовленные транзакции, которые не были совершены.
Слоты статической репликации.
См. Мое сообщение в блоге для подробностей.
У меня проблема.
Для понимания проблемы рассмотрите следующий поток:
Тема 1 -
Многие потоки типа Thread-1 работают параллельно.
Тема 2 -
Временное решение. Если я закрываю все эти соединения, созданные Thread-2, используя pg_cancel_backend, тогда начнет работать пылесос.
Кроме того, мы неоднократно воссоздавали проблему и пробовали это решение, и это сработало.
Теперь есть следующие сомнения, на которые все еще не ответил.
Еще одно замечание:
@Erwin Brandstetter и @Laurenz Albe, если вы знаете, что есть ошибка, связанная с postgres/jdbc.
В конце концов, могут быть блокировки, ваш запрос может ввести в заблуждение:
SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity USING (pid)
WHERE relation = 'subscriber_offset_manager'::regclass
pg_locks.pid
может быть NULL, тогда объединение будет удалять строки. Руководство для Postgres 9.3:
Идентификатор процесса сервера, выполняющий или ожидающий эту блокировку, или null, если блокировка удерживается подготовленной транзакцией
Смелый акцент мой. (Тем не менее в pg 10.)
Получаете ли вы что-нибудь для простого запроса?
SELECT * FROM pg_locks
WHERE relation = 'subscriber_offset_manager'::regclass;
Это может объяснить, почему VACUUM
жалуется:
DETAIL: 67720 dead row versions cannot be removed yet.
Это, в свою очередь, указывает на проблемы в вашей логике приложений/запросах, блокируя больше строк, чем необходимо.
Моей первой идеей были бы длительные транзакции, когда даже простой SELECT
(приобретая низкий блокировку ACCESS SHARE
) может заблокировать VACUUM
от выполнения своей работы. 20 потоков параллельно могут цепляться и блокировать VACUUM
бесконечно. Держите транзакции (и их блокировки) как можно более краткими. И убедитесь, что ваши запросы оптимизированы и не блокируют больше строк, чем необходимо.
Еще одно замечание: уровни изоляции транзакций SERIALIZABLE
или REPEATABLE READ
значительно SERIALIZABLE
REPEATABLE READ
VACUUM
. Режим READ COMMITTED
умолчанию менее ограничительный, но VACUUM
все еще может быть заблокирован, как обсуждалось.
Связанные с: