Вы находитесь на странице: 1из 63

Узкие места PostgreSQL #2

Александр Коротков

Postgres Professional

2020

Александр Коротков Узкие места PostgreSQL #2 1 / 63


О докладе

▶ Коллекция кейсов, как постгрес внезапно и неожиданно для всех


загнулся.
▶ Первая часть лежит здесь: h ps://pgconf.ru/2019/247964
▶ В прошлый раз зашло не плохо, решил повторить тот же формат
со свежим материалом.

Александр Коротков Узкие места PostgreSQL #2 2 / 63


План

▶ Упёрлись в BufMappingLock
▶ Упёрлись в ProcArrayLock
▶ Коллизии в fast path locking

Александр Коротков Узкие места PostgreSQL #2 3 / 63


Кейс №1: (Почти) вечное ожидание
BufMappingLock

Александр Коротков Узкие места PostgreSQL #2 4 / 63


Воспроизведение: setup

▶ c5d.18xlarge (72 VCPU)


▶ postgresql.conf
shared_buffers = 8GB
synchronous_commit = off
max_connections = 300

create table test1 (id serial primary key,


value int8 not null);
create table test2 (id serial primary key,
value int8 not null);
insert into test1 (value)
(select i from generate_series(1, 30) i);

Александр Коротков Узкие места PostgreSQL #2 5 / 63


Воспроизведение: pgbench

▶ script1.sql
select * from test1 where id in (1,2, ... , 30);

▶ script2.sql
\set value random(1, 100000)
insert into test2 (value) values (:value);

▶ Запускаем в параллель
pgbench -M prepared -f script1.sql -c 150 \
-j 150 -T 1000000 -P 1 postgres
pgbench -M prepared -f script2.sql -c 1 \
-j 1 -T 1000000 -P 1 postgres

Александр Коротков Узкие места PostgreSQL #2 6 / 63


Наблюдаемое поведение

▶ script1.sql
Стабильно 64-65 kTPS.
▶ script2.sql
progress: 21.0 s, 2741.9 tps, lat 0.364 ms stddev 0.502
progress: 22.0 s, 2076.7 tps, lat 0.393 ms stddev 0.537
progress: 23.0 s, 0.0 tps, lat 0.000 ms stddev 0.000
progress: 24.0 s, 0.0 tps, lat 0.000 ms stddev 0.000
progress: 25.0 s, 0.0 tps, lat 0.000 ms stddev 0.000
.......................................................
progress: 846.0 s, 0.0 tps, lat 0.000 ms stddev 0.000

Было 2.5-3.5 kTPS, стало 0.


Александр Коротков Узкие места PostgreSQL #2 7 / 63
Кто виноват?

Александр Коротков Узкие места PostgreSQL #2 8 / 63


Ищем виновного: easy mode

# select query, wait_event_type, wait_event


from pg_stat_activity;
-[ RECORD 1 ]---+---------------------------------------
query | insert into test2 (value) values ($1);
wait_event_type | LWLock
wait_event | buffer_mapping

Александр Коротков Узкие места PostgreSQL #2 9 / 63


Кто такой buffer_mapping?

Александр Коротков Узкие места PostgreSQL #2 10 / 63


Buffer mapping: hash table
block_number => buffer_number
value

hash(value)

hash(value)
%
nbuckets

nbuckets – 1
1 2 3

......
......
......
......
......
......

Александр Коротков Узкие места PostgreSQL #2 11 / 63


Buffer mapping: shared hash table
block_number => buffer_number
value

hash(value)

hash(value)
%
nbuckets

nbuckets – 1
1 2 3 4 nbuckets – 2

Partition #1 Partition #2 Partition #N


LWLock LWLock LWLock

......
......
......
......
......
......

Александр Коротков Узкие места PostgreSQL #2 12 / 63


Кто такой LWLock?

Александр Коротков Узкие места PostgreSQL #2 13 / 63


LWLock: работа очереди (1/4)

Приём документов

А мне только
спросить

Я подаю ??? ???


документы

Александр Коротков Узкие места PostgreSQL #2 14 / 63


LWLock: работа очереди (2/4)

Приём документов

??? ???

Александр Коротков Узкие места PostgreSQL #2 15 / 63


LWLock: работа очереди (3/4)

???

???

Приём документов

Александр Коротков Узкие места PostgreSQL #2 16 / 63


LWLock: работа очереди (4/4)

Приём документов

Александр Коротков Узкие места PostgreSQL #2 17 / 63


LWLock: shared приходит вне очереди (1/2)

???

???

Приём документов

??? OK!

А мне тоже
только спросить
Александр Коротков Узкие места PostgreSQL #2 18 / 63
LWLock: shared приходит вне очереди (2/2)

???
???
???

Приём документов

Александр Коротков Узкие места PostgreSQL #2 19 / 63


Что может пойти не так?

Александр Коротков Узкие места PostgreSQL #2 20 / 63


Exclusive LWLock waiter starva on

???
???
???

Приём документов

??? Ох...
???
???
И нам тоже
только спросить
Александр Коротков Узкие места PostgreSQL #2 21 / 63
Что делать?

Александр Коротков Узкие места PostgreSQL #2 22 / 63


Решение 1: коронавирус

Приём документов

??? ???

Александр Коротков Узкие места PostgreSQL #2 23 / 63


Решение 1: техника

▶ В современных процессорах слишком много ядер! А Вы ещё


вставили слишком много процессоров в свой сервер!
▶ Купите (арендуйте) сервер по-хуже!
▶ Или ограничьте использование CPU со стороны PostgreSQL.

Александр Коротков Узкие места PostgreSQL #2 24 / 63


Решение 2: ограничить доступ

Тут и так слишком


много людей!
Идите на %&#!

Приём документов

??? ???

???

??? ???

Александр Коротков Узкие места PostgreSQL #2 25 / 63


Решение 2: техника

▶ У вас слишком много read-only нагрузки!


▶ Ограничьте read-only нагрузку, которая вызывает проблему.
▶ На уровне приложения

▶ Балансировщиком нагрузки: pgbouncer, odyssey, ...

Александр Коротков Узкие места PostgreSQL #2 26 / 63


Это же не наш метод!
Давайте чинить СУБД!

Александр Коротков Узкие места PostgreSQL #2 27 / 63


Решение 3: убрать конфликт

???
???
???

Приём документов  Справочная

???

???

Александр Коротков Узкие места PostgreSQL #2 28 / 63


Решение 3: техника

▶ Можно починить LWLock use cases.


▶ BufMappingLock: lockless trie for buffer mapping
▶ ProcArrayLock: CSN snapshots
▶ WALInsertLock: lockless queue for WAL writer
▶ Круто!
▶ Но трудоёмко, а значит долго. А нам нужно решение прямо
сейчас!

Александр Коротков Узкие места PostgreSQL #2 29 / 63


Решение 4: “честная очередь” (1/2)

???
???
???

Приём документов

??? В очередь, %&@*ь!


???
???
И нам тоже
только спросить
Александр Коротков Узкие места PostgreSQL #2 30 / 63
Решение 4: “честная очередь” (2/2)

???
???
???

Приём документов

??? ??? ???

Александр Коротков Узкие места PostgreSQL #2 31 / 63


Решение 4: техника

▶ Патч “more fair” LWLock: http://bit.ly/2uPUdpU


▶ После того, как проходит lwlock_shared_limit последовательных
shared locker’ов, переводим LWLock в “честный” режим.
▶ В “честном” режиме, shared locker’ы становятся в очередь.
▶ Когда очередь доходит до exclusive locker’а, он снимает
“честный” режим.

Александр Коротков Узкие места PostgreSQL #2 32 / 63


“More fair” LWLock benchmark: regression

Александр Коротков Узкие места PostgreSQL #2 33 / 63


“More fair” LWLock benchmark: наш кейс

▶ script1.sql
Стабильно 64-65 kTPS.
▶ script2.sql
Стабильно 2.7-3.0 kTPS.
▶ То, что надо!

Александр Коротков Узкие места PostgreSQL #2 34 / 63


Но патч не закоммичен!

Александр Коротков Узкие места PostgreSQL #2 35 / 63


Как использовать “more fair” LWLock

▶ Если есть $$$, то купить Postgres Pro Enterprise.


▶ Если нет $$$, то собрать себе PostgreSQL c патчем на свой страх и
риск.
▶ А ещё быть сознательным участником сообщества и поделиться
своим опытом в треде.
▶ И не забыть сказать: “Борис, Андрес, ты не прав!”.

Александр Коротков Узкие места PostgreSQL #2 36 / 63


Кейс №2: И ProcArrayLock туда же

Александр Коротков Узкие места PostgreSQL #2 37 / 63


Групповые оптимизации (1/3)

???
???
???

Приём документов

Давайте
всё мне!

Александр Коротков Узкие места PostgreSQL #2 38 / 63


Групповые оптимизации (2/3)

???
???
???

Приём документов

Александр Коротков Узкие места PostgreSQL #2 39 / 63


Групповые оптимизации (3/3)

Приём документов

Александр Коротков Узкие места PostgreSQL #2 40 / 63


Групповые оптимизации в PostgreSQL

▶ Оптимизация exclusive ProcArrayLock при commit’е (group


ProcArray clear xid) – PostgreSQL 9.6
▶ Оптимизация exclusive ClogControlLock (group clog update) –
PostgreSQL 11.
▶ Помогает, но не спасает!

Александр Коротков Узкие места PostgreSQL #2 41 / 63


Воспроизведение: pgbench

▶ Setup такой же как в прошлом кейсе


▶ script1.sql
select 1; select 2; ... select 30;

▶ Запускаем
pgbench -M prepared -f script1.sql -c 150 \
-j 150 -T 1000000 -P 1 postgres

Александр Коротков Узкие места PostgreSQL #2 42 / 63


Наблюдаемое поведение

▶ script1.sql
Стабильно 34-35 kTPS.
▶ Никто больше подключиться не может.
▶ Только 117 коннектов работают, 33 зависли на authen ca on.

Александр Коротков Узкие места PostgreSQL #2 43 / 63


Кто виноват?

Александр Коротков Узкие места PostgreSQL #2 44 / 63


ProcArrayLock

▶ Берётся shared на взятие снапшота.


▶ Берётся exclusive на коннект, на коммит транзакции.
▶ “SELECT const;” берёт снапшот, “;” не берёт (gotcha!).
▶ Бенчмарк “забил” ProcArrayLock наглухо.

Александр Коротков Узкие места PostgreSQL #2 45 / 63


Что делать?

Александр Коротков Узкие места PostgreSQL #2 46 / 63


Что делать с ProcArrayLock?

▶ Уменьшить нагрузку (см. предыдущий кейс).


▶ Использовать “more fair” LWLock (см. предыдущий кейс).
▶ Применить CSN патч: http://bit.ly/2S9ma3V
▶ Оптимизировать нагрузку!

Александр Коротков Узкие места PostgreSQL #2 47 / 63


Current snapshot model

Александр Коротков Узкие места PostgreSQL #2 48 / 63


CSN model

Александр Коротков Узкие места PostgreSQL #2 49 / 63


CSN benchmark: 90% read, 10% write

Александр Коротков Узкие места PostgreSQL #2 50 / 63


Оптимизируем нагрузку на ProcArrayLock

▶ script2.sql
select 1; ... select 30; select txid_current();

▶ txid_current() делает транзакцию “пишущей”, разбавляет


сплошной поток shared lock’ов.
▶ Стабильно 33-34 kTPS (˷3% замедление)
▶ Все подключились!

Александр Коротков Узкие места PostgreSQL #2 51 / 63


Кейс №3: Коллизия fast path locking

Александр Коротков Узкие места PostgreSQL #2 52 / 63


“Fastpath” locking

Приём документов Информация

А мне
достаточно изучить
информацию

Я подаю ??? ???


документы

Александр Коротков Узкие места PostgreSQL #2 53 / 63


Воспроизведение: setup

▶ Машина и postgresql.conf такие же как в прошлых кейсах


▶ pgbench -i -s 1000 postgres

▶ Функции отсюда https://gist.github.com/akorotkov/


fce8ec80e3b0bf113b68a82fe41294a3
▶ create table nocollision (i int);
select make_collision();

Александр Коротков Узкие места PostgreSQL #2 54 / 63


Воспроизведение: скрипты pgbench

▶ nocollision.sql
truncate nocollision;

▶ collision.sql
truncate collision;

Александр Коротков Узкие места PostgreSQL #2 55 / 63


Воспроизведение: запускаем pgbench

▶ Запускаем в параллель
pgbench -M prepared -S -c 150 \
-j 150 -T 1000000 -P 1 postgres
pgbench -M prepared -f nocollision.sql -c 10 \
-j 10 -T 1000000 -P 1 postgres

▶ Запускаем в параллель
pgbench -M prepared -S -c 150 \
-j 150 -T 1000000 -P 1 postgres
pgbench -M prepared -f collision.sql -c 10 \
-j 10 -T 1000000 -P 1 postgres

Александр Коротков Узкие места PostgreSQL #2 56 / 63


Наблюдаемое поведение

▶ -S – 830-840 kTPS
-f nocollision.sql – 200-250 TPS
▶ -S – 145-150 kTPS
-f collision.sql – 500-600 TPS

Александр Коротков Узкие места PostgreSQL #2 57 / 63


Что происходит?

Александр Коротков Узкие места PostgreSQL #2 58 / 63


Коллизия“fastpath” locking

Приём документов Информация

Перегородили всё! ???


Придётся стоять...

Александр Коротков Узкие места PostgreSQL #2 59 / 63


Что делать?

Александр Коротков Узкие места PostgreSQL #2 60 / 63


Как не попадать на коллизии fast path

▶ Не берите strong locks (> ShareUpdateExclusive) слишком часто.


▶ Если запросы, которые ограничиваются weak locks (<
ShareUpdateExclusive) висят с wait_type = ’lock_manager’ – это
подозрительно.
▶ Поменяйте oid и всё пройдёт :)

Александр Коротков Узкие места PostgreSQL #2 61 / 63


Вместо заключения.

Александр Коротков Узкие места PostgreSQL #2 62 / 63


Спасибо за внимание!

Александр Коротков Узкие места PostgreSQL #2 63 / 63

Вам также может понравиться