Двухфазные транзакции в PostgreSQL

«Пост-Грэс-Кью-Эл» свободная объектно-реляционная СУБД. Обмениваемся вопросами и ответами о её работе.
Ответить
AntonS
Сообщения: 130
Зарегистрирован: Пт июн 03, 2022 8:51 am

Двухфазные транзакции в PostgreSQL

Сообщение AntonS »

Возьмём для примера транзакцию с эксклюзивной блокировкой таблицы:

Код: Выделить всё

demo=# BEGIN WORK;
BEGIN
demo=*# LOCK TABLE demo.test IN ACCESS EXCLUSIVE MODE;
LOCK TABLE
demo=*# PREPARE TRANSACTION 'abc';
PREPARE TRANSACTION
Из документации:
PREPARE TRANSACTION подготавливает текущую транзакцию для двухфазной фиксации. После этой команды транзакция перестаёт быть связанной с текущим сеансом; её состояние полностью сохраняется на диске, и есть очень большая вероятность, что она будет успешно зафиксирована, даже если до этого времени работа базы данных будет прервана аварийно.

Информацию о двухфазных транзакциях содержит представление pg_prepared_xacts:

Код: Выделить всё

demo=# select * from pg_prepared_xacts;
 transaction | gid |           prepared            |  owner   |   database    | state3pc
-------------+-----+-------------------------------+----------+---------------+----------
      344330 | abc | 2024-11-29 07:57:32.597673+03 | postgres | demo          |
(1 row)
Видно, что файл на диске появился отложенно, через несколько минут после команды PREPARE TRANSACTION:
-bash-4.4$ cd /var/lib/pgsql/pgdata/pg_twophase
-bash-4.4$ ls -l
total 4
-rw------- 1 postgres postgres 172 Nov 29 07:59 000000000005410A

Документация отслеживания блокировок pg_locks содержит SELECT с левым внешним соединением (LEFT JOIN) pg_locks и pg_prepared_xacts.

Отслеживать ресурсы, блокируемые двухфазнымми транзакциями, можно так:

Код: Выделить всё

demo=# SELECT po.locktype, po.relation::regclass, po.mode, ppx.* FROM pg_locks pl JOIN pg_prepared_xacts ppx on pl.transactionid = ppx.transa
ction join pg_locks po on pl.virtualtransaction = po.virtualtransaction;
   locktype    |      relation      |        mode         | transaction | gid |           prepared            |  owner   |   database    | state3pc
---------------+--------------------+---------------------+-------------+-----+-------------------------------+----------+---------------+----------
 transactionid |                    | ExclusiveLock       |      344330 | abc | 2024-11-29 07:57:32.597673+03 | postgres | demo |
 relation      | test_servers_jsonb | AccessExclusiveLock |      344330 | abc | 2024-11-29 07:57:32.597673+03 | postgres | demo |
(2 rows)
Также двухфазные транзакции можно полностью отключить, указав значение параметра max_prepared_transactions = 0
Аватара пользователя
SQL*Plus
Сообщения: 358
Зарегистрирован: Ср апр 20, 2022 1:09 pm

Re: Двухфазные транзакции в PostgreSQL

Сообщение SQL*Plus »

AntonS писал(а): Пт ноя 29, 2024 10:32 am Из документации:
PREPARE TRANSACTION подготавливает текущую транзакцию для двухфазной фиксации.
После этой команды транзакция перестаёт быть связанной с текущим сеансом;
её состояние полностью сохраняется на диске, и есть очень большая вероятность,
что она будет успешно зафиксирована, даже если до этого времени работа базы данных
будет прервана аварийно.
Возникло два вопроса:

1) "...транзакция перестаёт быть связанной с текущим сеансом..."

Обеспечивается ли при этом уровень изоляции "Read Commited"?
Будут ли видны незафиксированные (uncommited) изменения данных:
- в том сеансе, где были выполнены эти изменения?
- во всех остальных сеансах?


2) "... есть очень большая вероятность ..."

То есть транзакция с двухфазной фиксацией (two phase commit) может быть не зафиксирована?
Гарантий фиксации нет?
Аватара пользователя
SQL*Plus
Сообщения: 358
Зарегистрирован: Ср апр 20, 2022 1:09 pm

Re: Двухфазные транзакции в PostgreSQL

Сообщение SQL*Plus »

Из документации:
Примечания

PREPARE TRANSACTION не предназначена для использования в приложениях или интерактивных сеансах.
Её задача — дать возможность внешнему менеджеру транзакций выполнять атомарные глобальные транзакции,
охватывающие несколько баз данных или другие транзакционные ресурсы.
Обычно применять PREPARE TRANSACTION следует только при разработке собственного менеджера транзакций.
Полезное пояснение-предупреждение.
AntonS
Сообщения: 130
Зарегистрирован: Пт июн 03, 2022 8:51 am

Re: Двухфазные транзакции в PostgreSQL

Сообщение AntonS »

1. Изоляция транзакции обеспечивается. Т.е. изменения никаким другим процессам не видны до момента фиксации.

2. Как и с обычной транзакцией, если в момент сбоя данные не попадут на диск, то она не будет зафиксирована. Выше уже отметил отложенную запись двухфазной транзакции в файл на диск. Если файл не запишется, то и ветвь двухфазной транзакция не зафиксируется.
Аватара пользователя
SQL*Plus
Сообщения: 358
Зарегистрирован: Ср апр 20, 2022 1:09 pm

Re: Двухфазные транзакции в PostgreSQL

Сообщение SQL*Plus »

AntonS писал(а): Пт ноя 29, 2024 1:33 pm 1. Изоляция транзакции обеспечивается. Т.е. изменения никаким другим процессам не видны до момента фиксации.
То есть незафиксированные (uncommited) изменения данных
НЕ будут видны в том сеансе, где были выполнены эти изменения?
Аватара пользователя
SQL*Plus
Сообщения: 358
Зарегистрирован: Ср апр 20, 2022 1:09 pm

Re: Двухфазные транзакции в PostgreSQL

Сообщение SQL*Plus »

AntonS писал(а): Пт ноя 29, 2024 1:33 pm 2. Как и с обычной транзакцией, если в момент сбоя данные не попадут на диск, то она не будет зафиксирована.
. . .
Если файл не запишется, то и ветвь двухфазной транзакция не зафиксируется.
Предположим, что одна ветвь не была зафиксирована.

Что будет с остальными ветвями двухфазной транзакции?
- Они будут зафиксированы?
- Будет выполнен откат изменений всех остальных ветвей?
- Другое?
AntonS
Сообщения: 130
Зарегистрирован: Пт июн 03, 2022 8:51 am

Re: Двухфазные транзакции в PostgreSQL

Сообщение AntonS »

SQL*Plus писал(а): Пт ноя 29, 2024 4:02 pm
AntonS писал(а): Пт ноя 29, 2024 1:33 pm 1. Изоляция транзакции обеспечивается. Т.е. изменения никаким другим процессам не видны до момента фиксации.
То есть незафиксированные (uncommited) изменения данных
НЕ будут видны в том сеансе, где были выполнены эти изменения?
После подготовки транзакции PREPARE TRANSACTION изменения не видны никаким процессам, даже в том сеансе, где они выполнялись:

Код: Выделить всё

demo=# BEGIN WORK;
BEGIN
demo=*# INSERT INTO test (id) VALUES (1);
INSERT 0 1
demo=*# PREPARE TRANSACTION 'abc';
PREPARE TRANSACTION
demo=# SELECT * FROM test;
 id
----
(0 rows)
Изменения становятся видны всем после подтверждения двухфазной транзакции целиком. Очевидно, что зафиксировать или отменить её может и другой сеанс:

Код: Выделить всё

demo=# COMMIT PREPARED 'abc';
COMMIT PREPARED
demo=# SELECT * FROM test;
 id
----
  1
(1 row)
AntonS
Сообщения: 130
Зарегистрирован: Пт июн 03, 2022 8:51 am

Re: Двухфазные транзакции в PostgreSQL

Сообщение AntonS »

SQL*Plus писал(а): Пт ноя 29, 2024 4:02 pm
AntonS писал(а): Пт ноя 29, 2024 1:33 pm 2. Как и с обычной транзакцией, если в момент сбоя данные не попадут на диск, то она не будет зафиксирована.
. . .
Если файл не запишется, то и ветвь двухфазной транзакция не зафиксируется.
Предположим, что одна ветвь не была зафиксирована.

Что будет с остальными ветвями двухфазной транзакции?
- Они будут зафиксированы?
- Будет выполнен откат изменений всех остальных ветвей?
- Другое?
Под "не зафиксируется" понимаю состояние, когда одна ветвь двухфазной транзакции не подверждена, но и не отменена. Если это так, то вся двухфазная транзакция будет ждать до тех пор, пока эта ветвь не завификсируется, изменения других ветвей также не будут видны до полной фиксации prepared транзакции.
При использовании двухфазных транзакции есть вероятность, что в случае сбоя они окажутся в неизвестном состоянии, и до их отмены будут блокировать ресурсы системы даже при рестарте базы данных.
Ответить