Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Анатомия конкурентного доступа к данным в PostgreSQL

Анатомия конкурентного доступа к данным в PostgreSQL

На физическом и прикладном уровнях

Victor Yegorov

May 31, 2018
Tweet

More Decks by Victor Yegorov

Other Decks in Technology

Transcript

  1. Обзор • Конкуренция и блокировки • Версионирование и его особенности

    • Блокировки при записи • Чтение в мультиверсионной СУБД • Диагностика
  2. Конкуренция в примере • европейский мобильный оператор • рейтинг в

    10 потоков • претензии к базе — медленно работает • в мониторинге чуть более 1 потока — где-то узкое место
  3. Конкуренция в примере • европейский мобильный оператор • рейтинг в

    10 потоков • претензии к базе — медленно работает • в мониторинге чуть более 1 потока — где-то узкое место • по факту — все проводки имеют контрагентом счёт компании
  4. И что же делать? • Не делать так! • Делать,

    но не так! “Доктор, вы мне советовали так не делать, но почему мне по-прежнему больно когда я так делаю ещё раз?”
  5. Зачем нужны блокировки? • реляционная СУБД обеспечивает ACID свойства •

    свойства A, C, I — сериалисериализация транзакций через двухфазовые блокировки (2PL)PL) • 2PL)PL проста в реализации, однако полностью блокирует доступ к ресурсу при записи
  6. Версионирование • если хранить несколько версий объекта, то не нужно

    ждать блокировку • писатели не блокируют читателей • писатели сериализуются по 2PL)PL • MVCC в терминах в PostgreSQL, добавлено в версии 6.5 (Июнь, 1999)
  7. Как было до MVCC? • блокировки всей таблицы • сохранились

    для всех DDL операций • ALTER TABLE … ADD COLUMN … DEFAULT NULL; • CONCURRENTLY для работы с индексами
  8. Что есть в настоящее время? • блокировки таблицы • блокировки

    записи в таблице • блокировки страниц • рекомендательные блокировки • http://bit.do/pg_locks
  9. Особенности реализации • видимость задаётся нижней и верхней границей, 32PL)-bit

    Xmin и Xmax • необходимо “морозить” старые записи, т.к. 4 миллиарда транзакций — сериалиэто быстро • версии только в хипе (UNDO) ) • необходимость вакуумирования • множественные ссылки в индексах
  10. На что обращать внимание? • нужно вакуумировать таблицы и “морозить”

    записи — не надо выключать или даже тормозить вакуум • негативный эффект от долгих транзакций — сериалистрогий контроль с принудительным завершением • множественные ссылки в индексах — сериалинеобходимо следить за “здоровьем” индексов
  11. Горячие цепочки • Heap-O) nly Tuples • индексы не меняются,

    если не меняется ни одна индексированная колонка • много индексов — сериалине всегда хорошо
  12. last_modified • Таблица с отслеживанием изменений: CREATE TABLE t (

    id integer NOT NULL, … last_modified timestamp NOT NULL ); CREATE INDEX i_t_modified ON t (last_modified); • выключает HO) T
  13. Запись и блокировки • запись не блокирует чтение • все

    пишущие запросы конкурируют за одинаковые ресурсы (2PL)PL) • база хранит блокировки записей в заголовке записи или в MultiXact структуре • FOR [NO KEY] UPDATE • FOR [KEY] SHARE
  14. Очередь в базе • SELECT FOR UPDATE для сериализации доступа

    • FOR UPDATE SKIP LOCKED для параллельной обработки • очередь неудобна для MVCC • рекомендуется использовать несколько таблиц в ротации, с TRUNCATE после переключения • лучше всего рассмотреть готовые решения — PGQ
  15. Чтение мультиверсионных данных • читающая транзакция видит снимок данных, “независимый”

    от пишущей активности • снимок зависит от уровня изоляции • READ COMMITTED проще для базы, но приводит к аномалиям • REPEATABLE READ и SERIALIZABLE избавляют от аномалий, но сложнее и возвращают ошибки при нарушении сериализации
  16. Повторяемое чтение • “из коробки” каждый запрос видит самые свежие

    данные, результаты могут отличатся в пределах транзакции • REPEATABLE READ используется pg_dump-ом для снятия логического снимка базы • подходит для сложных отчётов и выгрузки данных • пишущие запросы при конфликте видимости обрываются ошибкой сериализации
  17. Сериализация • отслеживание всех предикатов, не только блокирующих • используются

    для синхронизации сложных конкурентных систем • полная сериализация доступа через ошибки при нарушении • самый “простой” режим для клиентов
  18. Цвета-цветочки CREATE TABLE c ( id int NOT NULL PRIMARY

    KEY, color text NOT NULL); INSERT INTO c VALUES (1, 'white'), (2, 'black'); postgres=# SELECT * FROM c; id color -- ----- 1 white 2 black (2 rows)
  19. Цвета в повторяемом чтении -- 1 BEGIN ISOLATION LEVEL REPEATABLE

    READ; UPDATE c SET color='black' WHERE color='white'; COMMIT; -- committed -- 2 BEGIN ISOLATION LEVEL REPEATABLE READ; UPDATE c SET color='white' WHERE color='black'; COMMIT; -- committed
  20. Сериализация postgres=# BEGIN ISOLATION LEVEL SERIALIZABLE; postgres=# UPDATE c SET

    color='black' WHERE color='white'; -- -- wait for other transaction to commit -- postgres=# COMMIT; ERROR: could not serialize access due to read/write dependencies among transactions DETAIL: Reason code: Canceled on identification as a pivot, during commit attempt. HINT: The transaction might succeed if retried.
  21. Диагностика: сессии SELECT coalesce(wait_event_type = 'Lock', 'f') waiting, * FROM

    pg_stat_activity -- WHERE (clock_timestamp() - pg_stat_activity.xact_start) >'00:00:00.1'::interval AND pg_stat_activity.pid<>pg_backend_pid() -- ORDER BY coalesce(pg_stat_activity.xact_start, pg_stat_activity.query_start); • http://bit.do/db_activity
  22. Диагностика: блокировки query ---------------------------------------------- UPDATE b SET b_name='A One' WHERE

    b_id=1; . INSERT INTO a VALUES (3, 'Drei', now()); . UPDATE b SET b_name='The One' WHERE b_id=1; . . DELETE FROM a WHERE a_id=1; . ALTER TABLE a DROP CONSTRAINT p_a; . DROP TABLE b; • http://bit.do/locktree
  23. Как ещё наблюдать? • системные утилиты: top, iostat, ethstats, strace,

    perf • cнятие снимков wait_event_type и wait_event каждые 100мс • подготовить тест кейс и открыть баг-репорт