HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-19
1 <p><strong>Иван Чувашов, DBA Okko и Southbridge, разберёт жизненные кейсы с PostgreSQL, которые помогут решить ваши проблемы.</strong></p>
1 <p><strong>Иван Чувашов, DBA Okko и Southbridge, разберёт жизненные кейсы с PostgreSQL, которые помогут решить ваши проблемы.</strong></p>
2 <p>Иван Чувашов</p>
2 <p>Иван Чувашов</p>
3 <p>DBA Southbridge</p>
3 <p>DBA Southbridge</p>
4 <p><strong>Ситуация с idle in transaction</strong>- приложение открыло транзакцию, отправило изменения в базу данных, а закрыть транзакцию забыло, транзакция висит.</p>
4 <p><strong>Ситуация с idle in transaction</strong>- приложение открыло транзакцию, отправило изменения в базу данных, а закрыть транзакцию забыло, транзакция висит.</p>
5 <p>Как решать инженеру такие ситуации? В Интернете можно найти много статей на тему: что такое idle in transaction, с чем оно связано и даже на практике посмотреть примеры реализации этой ситуации, но не получите самую главную информацию - как решать такие проблемы?</p>
5 <p>Как решать инженеру такие ситуации? В Интернете можно найти много статей на тему: что такое idle in transaction, с чем оно связано и даже на практике посмотреть примеры реализации этой ситуации, но не получите самую главную информацию - как решать такие проблемы?</p>
6 <p>Иван Чувашов</p>
6 <p>Иван Чувашов</p>
7 <p>Ведущий инженер Okko</p>
7 <p>Ведущий инженер Okko</p>
8 <p><strong></strong>У нас была ситуация, когда появились idle in transaction, и приложение начало тормозить - пул подключений в базе данных был забит. Они блокировали ресурсы, и нам нужно было срочно принимать какое-то решение, мы пошли самым простым путём, который напрашивается и предлагается вашему вниманию.</p>
8 <p><strong></strong>У нас была ситуация, когда появились idle in transaction, и приложение начало тормозить - пул подключений в базе данных был забит. Они блокировали ресурсы, и нам нужно было срочно принимать какое-то решение, мы пошли самым простым путём, который напрашивается и предлагается вашему вниманию.</p>
9 <p>Первый вариант, который может быть - это выполнение команд select pg_cancel_backend(pid) from pg_stat_activity where state = 'idle in transactions' and datname = 'название_БД'; или select pg_terminate_backend(pid) from pg_stat_activity where state = 'idle in transactions' and datname = 'название_БД';</p>
9 <p>Первый вариант, который может быть - это выполнение команд select pg_cancel_backend(pid) from pg_stat_activity where state = 'idle in transactions' and datname = 'название_БД'; или select pg_terminate_backend(pid) from pg_stat_activity where state = 'idle in transactions' and datname = 'название_БД';</p>
10 <p>Отличие данных функций друг от друга можно почитать тут:<a>https://postgrespro.ru/docs/postgresql/13/functions-admin#FUNCTIONS-ADMIN-SIGNAL-TABLE</a>.</p>
10 <p>Отличие данных функций друг от друга можно почитать тут:<a>https://postgrespro.ru/docs/postgresql/13/functions-admin#FUNCTIONS-ADMIN-SIGNAL-TABLE</a>.</p>
11 <p>Иван Чувашов</p>
11 <p>Иван Чувашов</p>
12 <p>Сертифицированный администратор PostgreSQL: PostgresPro, 10 уровень "Эксперт"</p>
12 <p>Сертифицированный администратор PostgreSQL: PostgresPro, 10 уровень "Эксперт"</p>
13 <p><strong></strong><strong>А может ли упасть PostgreSQL?</strong>Когда выполняете pg_terminate_backend - это не нулевая вероятность. Допустим, у вас есть процесс, который считывает данные и вы выполняете команду pg_terminate_backend, запрос подтягивает эти же данные в оперативную память PostgreSQL. Если в результате данные стали грязными, то их нельзя считывать другим процессам. Поэтому postmaster-у нужно очистить оперативную память, что он и делает, перезагружая себя.</p>
13 <p><strong></strong><strong>А может ли упасть PostgreSQL?</strong>Когда выполняете pg_terminate_backend - это не нулевая вероятность. Допустим, у вас есть процесс, который считывает данные и вы выполняете команду pg_terminate_backend, запрос подтягивает эти же данные в оперативную память PostgreSQL. Если в результате данные стали грязными, то их нельзя считывать другим процессам. Поэтому postmaster-у нужно очистить оперативную память, что он и делает, перезагружая себя.</p>
14 <p>Точечно отстреливать запросы, можно вызвать групповую команду по маске - очевидные плюсы. Но эти команды на самом деле не решают проблему с idle in transaction. Когда ситуация возникает на стороне бэкенда и мы выполнили команду, которая группой срубила запросы, то через некоторое время ситуация может повториться и тут же появятся от бэкенда запросы в статусе idle in transaction.</p>
14 <p>Точечно отстреливать запросы, можно вызвать групповую команду по маске - очевидные плюсы. Но эти команды на самом деле не решают проблему с idle in transaction. Когда ситуация возникает на стороне бэкенда и мы выполнили команду, которая группой срубила запросы, то через некоторое время ситуация может повториться и тут же появятся от бэкенда запросы в статусе idle in transaction.</p>
15 <p><b>Другой вариант - перезагрузка сервера PostgreSQL</b></p>
15 <p><b>Другой вариант - перезагрузка сервера PostgreSQL</b></p>
16 <p>Иван Чувашов</p>
16 <p>Иван Чувашов</p>
17 <p>Спикер курса по PostgeSQL</p>
17 <p>Спикер курса по PostgeSQL</p>
18 <p>Какие в этом решении могут быть минусы? Конечно же, остановка сервера. К тому же часто бывает, что на одном кластере находится не одна база, а несколько или даже с десяток разных баз.</p>
18 <p>Какие в этом решении могут быть минусы? Конечно же, остановка сервера. К тому же часто бывает, что на одном кластере находится не одна база, а несколько или даже с десяток разных баз.</p>
19 <p>При остановке сервера PostgreSQL мы убиваем подключения к другим базам или подключения других сервисов. Все это усугубляется ситуацией, когда приложение автоматически не может переподключится к базе. Да бывает и такое! Что может привести к каскадному эффекту в перезагрузке сервисов.</p>
19 <p>При остановке сервера PostgreSQL мы убиваем подключения к другим базам или подключения других сервисов. Все это усугубляется ситуацией, когда приложение автоматически не может переподключится к базе. Да бывает и такое! Что может привести к каскадному эффекту в перезагрузке сервисов.</p>
20 <p>Не знаю, если ли тут плюсы?</p>
20 <p>Не знаю, если ли тут плюсы?</p>
21 <p><strong>Небольшой лайхак.</strong>Чтобы быстрее перезапустить кластер, перед перезагрузкой выполните команду checkpoint.</p>
21 <p><strong>Небольшой лайхак.</strong>Чтобы быстрее перезапустить кластер, перед перезагрузкой выполните команду checkpoint.</p>
22 <p><b>Ещё вариант - перезагрузка бэкендов</b></p>
22 <p><b>Ещё вариант - перезагрузка бэкендов</b></p>
23 <p>Иван Чувашов</p>
23 <p>Иван Чувашов</p>
24 <p>13 лет работает с базами данных</p>
24 <p>13 лет работает с базами данных</p>
25 <p>Через pg_stat_activity определяем IP проблемного сервиса, с которого произошло подключение. Начинаем их перезагружать. В мире IT микроархитектуры этот процесс не будет являться существенной проблемой.</p>
25 <p>Через pg_stat_activity определяем IP проблемного сервиса, с которого произошло подключение. Начинаем их перезагружать. В мире IT микроархитектуры этот процесс не будет являться существенной проблемой.</p>
26 <p>В нашей ситуации получилось таким образом: увидели idle in transaction - начали пачками отключать запросы. Но количество соединений с базой данных не изменялось. Тут же появлялись новые в этом же статусе. Потом мы подумали: нужно перезагружать PostgreSQL.</p>
26 <p>В нашей ситуации получилось таким образом: увидели idle in transaction - начали пачками отключать запросы. Но количество соединений с базой данных не изменялось. Тут же появлялись новые в этом же статусе. Потом мы подумали: нужно перезагружать PostgreSQL.</p>
27 <p>От этой идеи быстро отказались, потому что у нас были другие сервисы и была вероятность, того, что после перезагрузки PostgreSQL они не поднимут заново соединение с базой. Поэтому мы через pg_stat_activity нашли бэкенды, которые забивают весь пул подключений, и их перезагрузили.</p>
27 <p>От этой идеи быстро отказались, потому что у нас были другие сервисы и была вероятность, того, что после перезагрузки PostgreSQL они не поднимут заново соединение с базой. Поэтому мы через pg_stat_activity нашли бэкенды, которые забивают весь пул подключений, и их перезагрузили.</p>
28 <p>Еще есть другой вариант, не рассмотренный нами выше. Если вы используете инструмент управления пулом соединений,<a>например pgbouncer</a>, то ситуация решилась бы довольно просто:</p>
28 <p>Еще есть другой вариант, не рассмотренный нами выше. Если вы используете инструмент управления пулом соединений,<a>например pgbouncer</a>, то ситуация решилась бы довольно просто:</p>
29 <ul><li>установка pgbouncer на паузу -<a>команда pause</a>;</li>
29 <ul><li>установка pgbouncer на паузу -<a>команда pause</a>;</li>
30 <li>перезагрузка сервера PostgreSQL;</li>
30 <li>перезагрузка сервера PostgreSQL;</li>
31 <li>снятие pgbouncer с паузы - команда resume.</li>
31 <li>снятие pgbouncer с паузы - команда resume.</li>
32 </ul><p>В другом известном инструменте управления пулом соединений<a>Odyssey</a>функционал, связанный с pause<a>пока не реализован</a>, что может ограничивать его использование в нагруженных проектах.</p>
32 </ul><p>В другом известном инструменте управления пулом соединений<a>Odyssey</a>функционал, связанный с pause<a>пока не реализован</a>, что может ограничивать его использование в нагруженных проектах.</p>
33 <p><strong>ЕЩЁ</strong></p>
33 <p><strong>ЕЩЁ</strong></p>
34 <p>В августе 2021 провели митап с Иваном по нюансам работы с PostgreSQL.</p>
34 <p>В августе 2021 провели митап с Иваном по нюансам работы с PostgreSQL.</p>
35 <p>Иван Чувашов</p>
35 <p>Иван Чувашов</p>
36 <p>Больше 6 лет работает архитектором БД и DBA</p>
36 <p>Больше 6 лет работает архитектором БД и DBA</p>
37 <p>СУБД PostgreSQL работает с диском, оперативной памятью, процессором. Если выходит аппаратная часть оборудования, то идём и чиним. Но иногда бывают и скрытые проблемы, например сбой в дисковом массиве, который мы можем заметить не сразу, можем вообще не знать об этом.</p>
37 <p>СУБД PostgreSQL работает с диском, оперативной памятью, процессором. Если выходит аппаратная часть оборудования, то идём и чиним. Но иногда бывают и скрытые проблемы, например сбой в дисковом массиве, который мы можем заметить не сразу, можем вообще не знать об этом.</p>
38 <p>Давайте воспроизведем проблему сбоя дисковой подсистемы, затем покажем её решение. У нас есть PostgreSQL - тринадцатая версия. Создадим базу и инициализируем<a>pgbench</a>. Она существует, чтобы нагружать сервер, снимать метрики производительности. Но нам она нужна для других целей.</p>
38 <p>Давайте воспроизведем проблему сбоя дисковой подсистемы, затем покажем её решение. У нас есть PostgreSQL - тринадцатая версия. Создадим базу и инициализируем<a>pgbench</a>. Она существует, чтобы нагружать сервер, снимать метрики производительности. Но нам она нужна для других целей.</p>
39 <p>Рассмотрим таблицу pgbench_branches, в ней есть три поля и одна запись.</p>
39 <p>Рассмотрим таблицу pgbench_branches, в ней есть три поля и одна запись.</p>
40 <p>Найдем, где находится физически эта таблица на диске: psql -p5432 -d test -c "select pg_relation_filepath('pgbench_branches')";</p>
40 <p>Найдем, где находится физически эта таблица на диске: psql -p5432 -d test -c "select pg_relation_filepath('pgbench_branches')";</p>
41 <p>Остановим кластер PostgreSQL. Откроем файл base/16839/16853 и допишем любой текст в середине файла. Сохраним его.</p>
41 <p>Остановим кластер PostgreSQL. Откроем файл base/16839/16853 и допишем любой текст в середине файла. Сохраним его.</p>
42 <p>Можно воспользоваться просто командой:sed -i 's/@/@123@/' ~/13/main/base/16839/16853</p>
42 <p>Можно воспользоваться просто командой:sed -i 's/@/@123@/' ~/13/main/base/16839/16853</p>
43 <p>Запустим PostgreSQL. Попробуем прочитать данные из таблицы.</p>
43 <p>Запустим PostgreSQL. Попробуем прочитать данные из таблицы.</p>
44 <p>В таблице также одна запись, но теперь в ней просто пустые строки.</p>
44 <p>В таблице также одна запись, но теперь в ней просто пустые строки.</p>
45 <p>Мы знаем, что файл у нас поврежден, но при этом PostgreSQL об этом не знает, и это достаточно серьезная проблема, с которой можно встретится в PostgreSQL.</p>
45 <p>Мы знаем, что файл у нас поврежден, но при этом PostgreSQL об этом не знает, и это достаточно серьезная проблема, с которой можно встретится в PostgreSQL.</p>
46 <p>Как проблему можно решить? Если мы посмотрим: включена ли у нас контрольная сумма страниц данных в кластере, то мы увидим, что off. Когда PostgreSQL обращается к данным, он рассчитывает контрольную сумму данных страницы, сравнивая её с сохраненной в заголовке страницы, и если она не соответствует, то он выдаёт ошибку.</p>
46 <p>Как проблему можно решить? Если мы посмотрим: включена ли у нас контрольная сумма страниц данных в кластере, то мы увидим, что off. Когда PostgreSQL обращается к данным, он рассчитывает контрольную сумму данных страницы, сравнивая её с сохраненной в заголовке страницы, и если она не соответствует, то он выдаёт ошибку.</p>
47 <p>Насколько это просаживает перформанс? Есть статистика, что - от одного до трёх процентов, но при этом вы точно знаете, что данные у вас повреждены или не повреждены. Это стоит того, чтобы включать контрольную сумму данных у себя. В девелоперской базе неважно. В препроде на ваше усмотрение. А в продовской обязательно должно быть включено.</p>
47 <p>Насколько это просаживает перформанс? Есть статистика, что - от одного до трёх процентов, но при этом вы точно знаете, что данные у вас повреждены или не повреждены. Это стоит того, чтобы включать контрольную сумму данных у себя. В девелоперской базе неважно. В препроде на ваше усмотрение. А в продовской обязательно должно быть включено.</p>
48 <p>Иван Чувашов</p>
48 <p>Иван Чувашов</p>
49 <p>Поддерживает техническую инфраструктуру компании Окко (dev, preprod, prod) в части баз данных</p>
49 <p>Поддерживает техническую инфраструктуру компании Окко (dev, preprod, prod) в части баз данных</p>
50 <p>В двенадцатой версии появилась хорошая утилита pg_checksums. Если раньше до двенадцатой версии вам приходилось создавать новый кластер уже с включенной контрольной суммой данных и в него переносить данные, то с двенадцатой версии можно выключить текущий сервер PostgreSQL и запустить эту утилиту, и она просмотрит все страницы и запишет в заголовках контрольные суммы данных.</p>
50 <p>В двенадцатой версии появилась хорошая утилита pg_checksums. Если раньше до двенадцатой версии вам приходилось создавать новый кластер уже с включенной контрольной суммой данных и в него переносить данные, то с двенадцатой версии можно выключить текущий сервер PostgreSQL и запустить эту утилиту, и она просмотрит все страницы и запишет в заголовках контрольные суммы данных.</p>
51 <p>Спросите про прострой? Она настолько производительна, что будет упираться в ваш диск. Когда мы переводили кластер полтора-терабайтный во включенную контрольную сумму данных, у нас это заняло сорок минут.</p>
51 <p>Спросите про прострой? Она настолько производительна, что будет упираться в ваш диск. Когда мы переводили кластер полтора-терабайтный во включенную контрольную сумму данных, у нас это заняло сорок минут.</p>
52 <p>Проделаем ту же процедуру с повреждением данных, что и ранее.</p>
52 <p>Проделаем ту же процедуру с повреждением данных, что и ранее.</p>
53 <p>И теперь если прочитаем данные из таблицы pgbench_branches увидим, что у нас появилась ошибка о несовпадении контрольных сумм.</p>
53 <p>И теперь если прочитаем данные из таблицы pgbench_branches увидим, что у нас появилась ошибка о несовпадении контрольных сумм.</p>
54 <p>Но если мы всё-таки хотим извлечь эти данные, то есть флаг ignore_checksum_failure. Когда мы его включаем, у нас выдаётся предупреждение, что контрольная сумма данных не совпадает, но запрос исполняется.</p>
54 <p>Но если мы всё-таки хотим извлечь эти данные, то есть флаг ignore_checksum_failure. Когда мы его включаем, у нас выдаётся предупреждение, что контрольная сумма данных не совпадает, но запрос исполняется.</p>
55 <p>Часто приложения используют только оперативные данные. PostgreSQL не обращается к старым страницам данных. И если в них есть повреждения, то мы можем узнать об этом слишком поздно, когда в резервных копиях тоже будут содержаться они.</p>
55 <p>Часто приложения используют только оперативные данные. PostgreSQL не обращается к старым страницам данных. И если в них есть повреждения, то мы можем узнать об этом слишком поздно, когда в резервных копиях тоже будут содержаться они.</p>
56 <p>Для проверки каталога данных можно воспользоваться командой checkdb в утилите<a>pg_probackup</a>. Хотя данная утилита создана для создания/восстановления резервных копий, в ней есть дополнительный инструмент проверки рабочего каталога базы данных и целостности индексов.</p>
56 <p>Для проверки каталога данных можно воспользоваться командой checkdb в утилите<a>pg_probackup</a>. Хотя данная утилита создана для создания/восстановления резервных копий, в ней есть дополнительный инструмент проверки рабочего каталога базы данных и целостности индексов.</p>
57 <p>Иван Чувашов</p>
57 <p>Иван Чувашов</p>
58 <p>Строил отказоустойчивые кластеры на базе СУБД PostgreSQL и GreenPlum 6x;</p>
58 <p>Строил отказоустойчивые кластеры на базе СУБД PostgreSQL и GreenPlum 6x;</p>
59 <p><strong>Пример из жизни.</strong>Запросы шли в базу и некоторые их них повисали. На сутки, двое, трое. Потом пул запросов стало большим и они начал забирать всю оперативную память.<em>Приходил omm killer и убивал PostgreSQL.</em></p>
59 <p><strong>Пример из жизни.</strong>Запросы шли в базу и некоторые их них повисали. На сутки, двое, трое. Потом пул запросов стало большим и они начал забирать всю оперативную память.<em>Приходил omm killer и убивал PostgreSQL.</em></p>
60 <p>Контрольные суммы страниц не были включены на том кластере. Мы не предполагали, что данные повреждены (любые проверки утверждали, что каталог данных и индексы не содержит повреждений) и думали, что у нас сложный запрос, который пытается вытащить много данных, висит и занимает всю оперативную память (что являлось фантастическим предположением).</p>
60 <p>Контрольные суммы страниц не были включены на том кластере. Мы не предполагали, что данные повреждены (любые проверки утверждали, что каталог данных и индексы не содержит повреждений) и думали, что у нас сложный запрос, который пытается вытащить много данных, висит и занимает всю оперативную память (что являлось фантастическим предположением).</p>
61 <p>Предполагали три варианта:</p>
61 <p>Предполагали три варианта:</p>
62 <ul><li>что-то с картой видимостью,</li>
62 <ul><li>что-то с картой видимостью,</li>
63 <li>что-то с индексами на этой таблице,</li>
63 <li>что-то с индексами на этой таблице,</li>
64 <li>что-то с данными в самой таблице.</li>
64 <li>что-то с данными в самой таблице.</li>
65 </ul><p>Решили удалить индексы и посмотреть, что будет - как только мы это сделали у нас приложение перестало работать. Это был фейл - приложение не работало три часа. Но нам стало сразу ясно, где проблема. Индексы ссылали на данные, которых нет в БД (страница данных нулевого размера).</p>
65 </ul><p>Решили удалить индексы и посмотреть, что будет - как только мы это сделали у нас приложение перестало работать. Это был фейл - приложение не работало три часа. Но нам стало сразу ясно, где проблема. Индексы ссылали на данные, которых нет в БД (страница данных нулевого размера).</p>
66 <p><strong>Как вышли из ситуации?</strong>Создали новую пустую таблицу и по блокам перетаскивали данные со старой таблицы в новую. Потом били блоки на меньшего размера и так до тех пор пока не выявили семнадцать битых строк, для которых были ссылки в других таблицах, но в целевой отсутствовали.</p>
66 <p><strong>Как вышли из ситуации?</strong>Создали новую пустую таблицу и по блокам перетаскивали данные со старой таблицы в новую. Потом били блоки на меньшего размера и так до тех пор пока не выявили семнадцать битых строк, для которых были ссылки в других таблицах, но в целевой отсутствовали.</p>
67 <p><strong>ЕЩЁ</strong></p>
67 <p><strong>ЕЩЁ</strong></p>
68 <p><strong>23-25 сентября 2021 года Иван проводит второй поток обучения продвинутого курса по PostgreSQL.</strong></p>
68 <p><strong>23-25 сентября 2021 года Иван проводит второй поток обучения продвинутого курса по PostgreSQL.</strong></p>
69 <p>Кейс разбит на три ситуации и они о предотвращении проблем, а не исправлении.</p>
69 <p>Кейс разбит на три ситуации и они о предотвращении проблем, а не исправлении.</p>
70 <p>У нас есть три таблички: заказы, продукты и таблица, которая связывает многие ко многим. В какой-то момент времени бизнес решил, что нужно сравнивать значения в одно регистре (обратите внимание на тип у колонки id в таблице orders). Можно со стороны приложения переводить все данные к нижнему или верхнему регистру и делать сравнение в запросе. Но можно воспользоваться встроенным типом данных<a>citext</a>. Рассмотрим, как разработчики решили переходить на новый тип данных.</p>
70 <p>У нас есть три таблички: заказы, продукты и таблица, которая связывает многие ко многим. В какой-то момент времени бизнес решил, что нужно сравнивать значения в одно регистре (обратите внимание на тип у колонки id в таблице orders). Можно со стороны приложения переводить все данные к нижнему или верхнему регистру и делать сравнение в запросе. Но можно воспользоваться встроенным типом данных<a>citext</a>. Рассмотрим, как разработчики решили переходить на новый тип данных.</p>
71 <p>Иван Чувашов</p>
71 <p>Иван Чувашов</p>
72 <p>Регулярно выступает на IT-конференциях</p>
72 <p>Регулярно выступает на IT-конференциях</p>
73 <p>Первая команда у нас создаст эксклюзивную блокировку, которая дропнет constraint. Достаточно быстрая операция. Вторая - по изменению типа, он относится к одному виду типов, поэтому быстрее заменится, проблем с этим не будет. Далее меняем тип на связные таблицах и пытаемся создать constraint.</p>
73 <p>Первая команда у нас создаст эксклюзивную блокировку, которая дропнет constraint. Достаточно быстрая операция. Вторая - по изменению типа, он относится к одному виду типов, поэтому быстрее заменится, проблем с этим не будет. Далее меняем тип на связные таблицах и пытаемся создать constraint.</p>
74 <p>Что у нас получается - эксклюзивная блокировка на две таблицы product orders и orders, чтобы данные не изменялись. И это будет выполняться в одном потоке. Когда у нас 100-200 записей, то проблем нет - это доли секунды. Если записей стало больше, миллионы, тогда эти внешний ключ будет накатываться очень долго.</p>
74 <p>Что у нас получается - эксклюзивная блокировка на две таблицы product orders и orders, чтобы данные не изменялись. И это будет выполняться в одном потоке. Когда у нас 100-200 записей, то проблем нет - это доли секунды. Если записей стало больше, миллионы, тогда эти внешний ключ будет накатываться очень долго.</p>
75 <p>Разработчики выкатывают релиз, и у нас останавливается сервис. Моя была ошибка, что пропустил этот pull request. Разобрались, срубили запрос. Ночью мы остановили сервис бэкенда, накатили sql-скрипты.</p>
75 <p>Разработчики выкатывают релиз, и у нас останавливается сервис. Моя была ошибка, что пропустил этот pull request. Разобрались, срубили запрос. Ночью мы остановили сервис бэкенда, накатили sql-скрипты.</p>
76 <p>Какие еще есть варианты решения? Можно воспользоваться конструкцией: ADD CONSTRAINT ... NOT VALID VALIDATE CONSTRAINT В этом случае будут наложены более легкие блокировки.</p>
76 <p>Какие еще есть варианты решения? Можно воспользоваться конструкцией: ADD CONSTRAINT ... NOT VALID VALIDATE CONSTRAINT В этом случае будут наложены более легкие блокировки.</p>
77 <p>Вариант 2, более специфичный, но рабочий. С десятой версии Postgres появилась логическая репликация product_orders в product_orders_replic, в которой уже есть внешний ключ product_orders_product_id_fkey. Когда мы скопировали все данные, мы взяли и поменяли таблички: product_orders -&gt; product_orders_tmp, product_orders_replic -&gt; product_orders. Это можно делать всё в одной транзакции, и будет достаточно быстро.</p>
77 <p>Вариант 2, более специфичный, но рабочий. С десятой версии Postgres появилась логическая репликация product_orders в product_orders_replic, в которой уже есть внешний ключ product_orders_product_id_fkey. Когда мы скопировали все данные, мы взяли и поменяли таблички: product_orders -&gt; product_orders_tmp, product_orders_replic -&gt; product_orders. Это можно делать всё в одной транзакции, и будет достаточно быстро.</p>
78 <p><b><strong><strong>Ситуация номер два, из жизни</strong></strong></b></p>
78 <p><b><strong><strong>Ситуация номер два, из жизни</strong></strong></b></p>
79 <p>Иван Чувашов</p>
79 <p>Иван Чувашов</p>
80 <p>Спикер курса по PostgeSQL</p>
80 <p>Спикер курса по PostgeSQL</p>
81 <p>Представим, что есть таблички folders и folder_files. Мы хотим пробежаться по всем подпапкам и вытаскивать файлы, которые там есть. Когда у нас десятки-сотни тысяч записей, то проблем нет. Но когда появляются десятки миллионов записей, то тут нужно искать другие способы раскрутки дерева.</p>
81 <p>Представим, что есть таблички folders и folder_files. Мы хотим пробежаться по всем подпапкам и вытаскивать файлы, которые там есть. Когда у нас десятки-сотни тысяч записей, то проблем нет. Но когда появляются десятки миллионов записей, то тут нужно искать другие способы раскрутки дерева.</p>
82 <p>Но у нас был простой рекурсивный цикл. Что произошло? По каким-то причинам оптимизатор решил не использовать индекс, а делать полное сканирование таблицы folders. На каждом шаге создавать временные файлы большого размера на диске. Что привело к остановке базы данных из-за отсутствия места.</p>
82 <p>Но у нас был простой рекурсивный цикл. Что произошло? По каким-то причинам оптимизатор решил не использовать индекс, а делать полное сканирование таблицы folders. На каждом шаге создавать временные файлы большого размера на диске. Что привело к остановке базы данных из-за отсутствия места.</p>
83 <p>Было выбрано решение - разделить запрос на два:</p>
83 <p>Было выбрано решение - разделить запрос на два:</p>
84 <ul><li>отдельно рекурсивное cte, ограничив его по уровню вложенности;</li>
84 <ul><li>отдельно рекурсивное cte, ограничив его по уровню вложенности;</li>
85 <li>отдельно маппинг результата cte с данными.</li>
85 <li>отдельно маппинг результата cte с данными.</li>
86 </ul><p>Тут можно предложить много способов оптимизации. Например, если дерево не меняется, то использовать не рекурсию, а вложенные интервалы. Но я не видел такой практической реализации.</p>
86 </ul><p>Тут можно предложить много способов оптимизации. Например, если дерево не меняется, то использовать не рекурсию, а вложенные интервалы. Но я не видел такой практической реализации.</p>
87 <p><b><strong><strong><strong>Ситуация три - немного о другом</strong></strong></strong></b></p>
87 <p><b><strong><strong><strong>Ситуация три - немного о другом</strong></strong></strong></b></p>
88 <p>Иван Чувашов</p>
88 <p>Иван Чувашов</p>
89 <p>Ведущий инженер Okko</p>
89 <p>Ведущий инженер Okko</p>
90 <p>Производительность базы данных сильно снизилась, что привело к деградации приложения. Анализ мониторинга железа не показывал явных проблем с производительность.</p>
90 <p>Производительность базы данных сильно снизилась, что привело к деградации приложения. Анализ мониторинга железа не показывал явных проблем с производительность.</p>
91 <p>Загрузка CPU доходит до полтинника. Проблемы наблюдаются достаточно давно. Нагрузка 50% - это не критично. Нагрузка по диску каких-то 400 ops.</p>
91 <p>Загрузка CPU доходит до полтинника. Проблемы наблюдаются достаточно давно. Нагрузка 50% - это не критично. Нагрузка по диску каких-то 400 ops.</p>
92 <p>Пик в районе трёх часов не относится к данной ситуации</p>
92 <p>Пик в районе трёх часов не относится к данной ситуации</p>
93 <p>Смотрим логи, а там постоянно такие записи.Ставка 62 секунды. Копаем дальше, смотрим различные метрики. И видим, что в таблице items отсутствуют первичный ключ. При вставке данных в таблицу history из-за внешнего ключа проверялось наличие записи в таблице items. Починили.</p>
93 <p>Смотрим логи, а там постоянно такие записи.Ставка 62 секунды. Копаем дальше, смотрим различные метрики. И видим, что в таблице items отсутствуют первичный ключ. При вставке данных в таблицу history из-за внешнего ключа проверялось наличие записи в таблице items. Починили.</p>
94 <p>Проблему не решило. Копаем дальше, смотрим представление pg_statio_all_tables и раскрываем всю суть.</p>
94 <p>Проблему не решило. Копаем дальше, смотрим представление pg_statio_all_tables и раскрываем всю суть.</p>
95 <p>Иван Чувашов</p>
95 <p>Иван Чувашов</p>
96 <p>DBA Southbridge</p>
96 <p>DBA Southbridge</p>
97 <p>Запрос select * from pg_statio_all_tables показывает кто генерит большую нагрузку на диск. Первая строчка history_text_default. В дефолтовую секцию ничего не должно писаться, но именно она создает нагрузку на диск. А количество чтений с диска на три порядка больше, чем в позиции на втором месте. Дефолтовая секция, большое количество чтений с диска - и мы понимаем, что перестало работать секционирование таблицы history_text.</p>
97 <p>Запрос select * from pg_statio_all_tables показывает кто генерит большую нагрузку на диск. Первая строчка history_text_default. В дефолтовую секцию ничего не должно писаться, но именно она создает нагрузку на диск. А количество чтений с диска на три порядка больше, чем в позиции на втором месте. Дефолтовая секция, большое количество чтений с диска - и мы понимаем, что перестало работать секционирование таблицы history_text.</p>
98 <p>Мы использовали расширение pg_partman, пересобрали табличку history_text. По ссылке можно найти, как мы это сделали:<a>https://github.com/Doctorbal/zabbix-postgres-partitioning#zabbiz-history-and-trends-tables</a>.</p>
98 <p>Мы использовали расширение pg_partman, пересобрали табличку history_text. По ссылке можно найти, как мы это сделали:<a>https://github.com/Doctorbal/zabbix-postgres-partitioning#zabbiz-history-and-trends-tables</a>.</p>
99 <p>Как только мы устранили проблему, деградация системы прекратилась и приложение заработало.</p>
99 <p>Как только мы устранили проблему, деградация системы прекратилась и приложение заработало.</p>
100 <p><b>Надеемся, что кейсы были полезны.</b><strong></strong></p>
100 <p><b>Надеемся, что кейсы были полезны.</b><strong></strong></p>
101 <p><strong>А вот, что ждёт инженеров, которые пройдут продвинутый курс Ивана по PostgreSQL:</strong>- Научитесь оценивать состояние кластера в критический момент, принимать быстрые и эффективные решения по обеспечению работоспособности кластера.</p>
101 <p><strong>А вот, что ждёт инженеров, которые пройдут продвинутый курс Ивана по PostgreSQL:</strong>- Научитесь оценивать состояние кластера в критический момент, принимать быстрые и эффективные решения по обеспечению работоспособности кластера.</p>
102 <p>- Узнаете, как внедрить новое оптимальное архитектурное решение в своей команде, а также сможете лидировать этот процесс.- сэкономите компании время и деньги путем оптимизации процессов администрирования.</p>
102 <p>- Узнаете, как внедрить новое оптимальное архитектурное решение в своей команде, а также сможете лидировать этот процесс.- сэкономите компании время и деньги путем оптимизации процессов администрирования.</p>
103 <p>- Поймете, как действовать в случае критических ситуаций с базой данных PostgreSQL и будете знать, где и с помощью какого алгоритма искать проблему.<strong>Это всё тоже написано на странице курса, а ещё там есть программа и немного о формате обучения:<a>https://slurm.club/3zk7PGq</a>.</strong></p>
103 <p>- Поймете, как действовать в случае критических ситуаций с базой данных PostgreSQL и будете знать, где и с помощью какого алгоритма искать проблему.<strong>Это всё тоже написано на странице курса, а ещё там есть программа и немного о формате обучения:<a>https://slurm.club/3zk7PGq</a>.</strong></p>
104  
104