- •Предисловие
- •Об этой книге
- •Глава 1. Обзор статистики
- •Внутреннее устройство PostgreSQL
- •Установка соединений и работа сеансов
- •Запросы как базовая единица рабочей нагрузки
- •Планирование и выполнение запросов
- •Ввод-вывод при выполнении запросов
- •Журнал сообщений СУБД
- •Репликация изменений
- •Архивирование журнала предзаписи
- •Фоновая синхронизация данных
- •Автоочистка
- •Интерфейс статистики
- •Статистика как отправная точка инструментов мониторинга
- •Особенности статистики
- •Тестовое окружение
- •Глава 2. Статистика активности
- •Ключ к пониманию происходящего в СУБД
- •Взаимодействие клиента и сервера
- •Источники информации об активности
- •Представление pg_stat_activity
- •Представление pg_locks
- •Особенности pg_stat_activity и pg_locks
- •Представление pg_stat_database
- •Подключенные клиенты
- •Отслеживание клиентских сеансов
- •Транзакционная активность
- •Статусы завершения сеансов
- •Состояния сеансов
- •Отслеживание состояний
- •Ожидания и блокировки
- •Отслеживание состояний с учетом ожиданий
- •Взаимоблокировки
- •Бездействующие транзакции
- •Время выполнения запросов и транзакций
- •Отслеживание времени ожидания блокировок
- •Использование pg_locks.waitstart
- •Использование pg_stat_activity.state_change
- •Дерево блокировок
- •Глава 3. Выполнение запросов и функций
- •Зачем нужен мониторинг запросов
- •Расширение pg_stat_statements
- •Метаданные запроса
- •Планирование запроса
- •Исполнение запроса
- •Сквозная идентификация с queryid
- •Построение отчетов на основе pg_stat_statements
- •Представление pg_stat_statements_info
- •Выполнение процедур и функций
- •Глава 4. Базы данных
- •Иерархия объектов СУБД
- •Кластер баз данных
- •Табличные пространства
- •Базы данных
- •Схемы
- •Таблицы и индексы
- •TOAST
- •События в кластере баз данных
- •Рабочая нагрузка в отношении таблиц и индексов
- •Ошибки и нежелательные события
- •Функции для работы с объектами СУБД
- •Определение размеров объектов СУБД
- •Размещение объектов в файловой системе
- •Глава 5. Область общей памяти и ввод-вывод
- •Анализ общей памяти
- •Представление pg_buffercache
- •Представление pg_shmem_allocations
- •Анализ памяти клиентских процессов
- •Оценка использования SLRU-кешей
- •Ввод-вывод в контексте объектов СУБД
- •Базы данных
- •Ввод-вывод в контексте выполнения запросов
- •Временные файлы
- •Уровень баз данных
- •Ввод-вывод при выполнении запросов
- •Отслеживание в журнале сообщений
- •Отслеживание активных временных файлов
- •Ввод-вывод фоновых процессов
- •Глава 6. Журнал упреждающей записи
- •Отслеживание активности в журнале
- •Представление pg_stat_wal
- •Представление pg_stat_statements
- •Архивирование журнала
- •Представление pg_stat_archiver
- •Очередь архивирования
- •Глава 7. Репликация
- •Обзор репликации
- •Инструменты отслеживания репликации
- •Представление pg_stat_replication
- •Представление pg_stat_wal_receiver
- •Cлоты репликации и pg_replication_slots
- •Публикации и подписки
- •Конфликты восстановления
- •Глава 8. Очистка
- •Введение в очистку
- •Особенности очистки на практике
- •Когда выполняется автоочистка?
- •Статистика выполнения очистки
- •Счетчик транзакций и предотвращение ошибок, связанных с его зацикливанием
- •Раздувание таблиц и индексов
- •Отслеживание активных процессов очистки
- •Представление pg_stat_activity
- •Представление pg_stat_progress_vacuum
- •Глава 9. Ход выполнения операций
- •Представление pg_stat_progress_analyze
- •Представление pg_stat_progress_basebackup
- •Представление pg_stat_progress_cluster
- •Представление pg_stat_progress_create_index
- •Представление pg_stat_progress_copy
- •Предметный указатель
58 |
Глава 2. Статистика активности |
пытаться открыть новые соединения, что может привести к росту очереди ожидающих и достижению ограничения на одновременно разрешенные подключения. При достижении этого ограничения приложение не сможет подключиться к БД, что приведет к невозможности работы и приложения,и СУБД,и других приложений,которые также хотели бы установить соединение с СУБД.
Таким образом, состояние idle in transaction является потенциально опасным, и долгое пребывание процессов в этом состоянии может привести к негативным последствиям. Такие транзакции нужно отслеживать и устранять. В тактическом плане такие транзакции можно завершать автоматически через включение тайм-аута idle_in_transaction_session_timeout в настройках СУБД. Эту настройку можно сделать как глобально, на уровне общей конфигурации СУБД,такииндивидуально,науровнеотдельныхпользователейилибазданных.Другимвариантом может быть периодический запуск скриптов на основе функции pg_terminate_backend средствами утилиты cron. Такое решение может быть предпочтительным в случае, когда возможностейidle_in_transaction_session_timeout недостаточноитребуетсяболеетонкаянастройка тайм-аутов.Пример использования связки pg_terminate_backend и pg_stat_activity:
#SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE usename = 'pgbench' AND application_name = 'pgbench'
AND clock_timestamp() - coalesce(xact_start, query_start) > '00:01:00'::interval AND state ~ 'idle in transaction';
Такой запрос достаточно вызвать из psql.При необходимости список полей в SELECT или условия можно переопределить,а вывод результата сохранять,например,для анализа.
clock_timestamp vs now
Для определения длительности обычно принято вычитать отметку времени из текущего времени.В любой СУБД есть функция,которая выводиттекущее время.В PostgreSQLтакой функцией является хорошо известная now,однако ее особенностью является то,что она показывает время начала транзакции. Попробуйте вызвать now в транзакции несколько раз. Для целей же мониторинга рекомендуется использовать clock_timestamp, которая всегда показываеттекущую отметку времени.
2.6. Время выполнения запросов и транзакций
Рабочая нагрузка состоит из постоянного потока запросов и транзакций, и чем быстрее они выполняются, тем больше пропускная способность системы. Наблюдая за рабочей нагрузкой
2.6. Время выполнения запросов и транзакций |
59 |
можно сфокусироваться на отдельных единицах выполнения —транзакциях и запросах, и отслеживать появление продолжительных запросов и транзакций, нехарактерных для этой рабочей нагрузки. Оптимизация времени выполнения положительно сказывается на производительности независимо от типа рабочей нагрузки. Неважно, OLTP, OLAP или HTAP, оптимизация всегда направлена на сокращение времени выполнения запросов и уменьшение объема ресурсов,необходимыхдля их выполнения.Время выполнения запросов зависитоттаких факторов, как количество требуемых ресурсов, доступные СУБД ресурсы, сложность запроса, его параметры и план выполнения и т. п. Долгое выполнение команд может указывать на самые разные проблемы. Например, выбор планировщиком неэффективного плана может выражаться в долгом выполнении и избыточном использовании ресурсов. Долгие транзакции могут быть следствием плохого дизайна и проблем в управлении транзакциями на стороне приложения. С точки зрения приложений долгое выполнение операций в СУБД может приводить к тайм-аутам обработки запросов в самом приложении или эффекту зависания (если тайм-ауты не настроены), исчерпанию соединений к СУБД и аварийной остановке приложения.Врегулярныезадачиадминистраторавходитотслеживаниевременивыполнениякоманд, расследование и устранение причин долгой работы.Зачастую устранением причин DBA занимается совместно с командами разработки приложений.
Для отслеживания продолжительности выполнения команд и транзакций в pg_stat_activity есть несколько полей:
•xact_start — время начала транзакции. Значение может отсутствовать (NULL), если в данный момент нет активной транзакции или в транзакции произошла ошибка и при этом транзакция не была закрыта,—состояние idle in transaction (aborted);
•query_start — время начала текущего запроса (состояние active) или последнего выполненного запроса в сеансе (все прочие состояния).
Для получения информации о длительности выполнения запросов и транзакций можно использоватьтакой вариант запроса:
#SELECT pid,
CASE WHEN wait_event_type = 'Lock' THEN 'waiting' ELSE state END AS state, (clock_timestamp() - xact_start) AS xact_age,
(clock_timestamp() - query_start) AS query_age |
|
|
||||
FROM pg_stat_activity |
|
|
|
|
||
WHERE (clock_timestamp() - xact_start > '00:00:00'::interval) |
|
|||||
OR (clock_timestamp() - query_start > '00:00:00'::interval |
|
|||||
AND state = 'idle in transaction (aborted)') |
|
|
||||
ORDER BY coalesce(xact_start, query_start); |
|
|
|
|||
pid |
| |
state |
| |
xact_age |
| |
query_age |
-------- |
+ |
------------------------------- |
+----------------- |
|
+----------------- |
|
3878 |
| |
idle in transaction (aborted) | |
|
| 00:00:04.264773 |
||
242533 |
| |
active |
| 00:00:00.176216 | 00:00:00.174478 |
|||
241520 |
| |
active |
| 00:00:00.150633 | 00:00:00.149281 |
|||
242541 |
| |
waiting |
| 00:00:00.141747 | 00:00:00.139989 |
|||
241506 |
| |
waiting |
| 00:00:00.123768 | 00:00:00.122107 |
|||
241523 |
| |
active |
| 00:00:00.102864 | 00:00:00.101012 |
|||
60Глава 2. Статистика активности
Вэтом запросе есть несколько особенностей,на которые стоит обратить внимание:
•Дляопределениясостоянияприменяетсярасширеннаялогикасиспользованиемсобытий ожидания.Процессыстипомсобытияwait_event_type='Lock'расцениваютсякакпроцессы,ожидающие завершения конкурентных транзакций.
•Условие запроса отбирает именно транзакции, а не отдельные запросы: левая часть условия OR ищет активные транзакций, правая часть — отмененные (aborted), но не закрытые транзакции. И вот почему: запросы, даже если они выполняются отдельно, вне транзакций, на самом деле также используют транзакционный механизм и, по сути, являются транзакциями,состоящимиизоднойкоманды.Втакомслучаедажедляобычныхзапросов заполняется поле xact_start (которое в этом случае равно значению query_start). Поэтому нет смысла концентрироваться на поиске запросов, они попадут в результат в любом случае.
•В правом от OR условии для поиска отмененных транзакций используется поле state. Смысл его использования заключается в том, что в случае возникновения ошибки внутри транзакции значение xact_start устанавливается в NULL, но сама транзакция при этом остается открытой. Чтобы не потерять такие транзакции, следует ориентироваться на query_start—время запроса,который завершился ошибкой.
•Изменяя значение в интервале, можно исключать из результата совсем короткие транзакции.
Спомощью метрики postgres_activity_max_seconds можно получить максимальную длительностьтранзакции.Метрика содержит в себе несколько меток:
•user—пользователь,вызвавший активность;
•database—база данных,к которой подключен клиент;
•type—тип активности: пользовательский запрос или фоновое обслуживание (в случае автоочистки или сбора статистики для планировщика);
•state—состояние сеанса,согласно полю state с учетом состояния waiting.
Спомощью меток можно выполнить агрегацию нескольких метрик в необходимой проекции. Например, следующим запросом можно отобразить долгую активность по конкретным пользователям независимо оттипа активности,базы данных и состояния:
# max by (user) (postgres_activity_max_seconds{service_id="primary"})
На рис. 2.9 изображен пример графика на основе этого запроса. Из графика видно, что бóльшаячастьзапросовукладываетсявинтервалдо500миллисекунд.Отдельноотметилсяпроцесс автоочистки, который выполнялся на тот момент около четырех секунд. Важно отметить, что эта метрика и график на ее основе показывают не абсолютно всю активность, происходящую в СУБД,а лишьту,что была в момент опроса pg_stat_activity.
