- •Предисловие
- •Об этой книге
- •Глава 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
- •Предметный указатель
44Глава 2. Статистика активности
Теперь взглянем на то,к каким базам данных выполнены подключения (рис. 2.4).
Рис. 2.4.Количество подключений к базам данных
Изприведенногографикастановитсяочевидным,чтопочтивсесоединенияустановленыкБД pgbench и это основная БД, на которой сосредоточена рабочая нагрузка. Совсем небольшая часть соединений установлена к БД postgres; скорее всего, эти соединения также устанавливаются экспортером метрик.
В зависимости от информативности метрик и используемых меток можно строить и другие проекции. Например, при широком использовании application_name со стороны прикладных приложений эту информацию можно также экспортировать в метках метрик и вывести соответствующий график.
Транзакционная активность
Запросы—это базовая единица рабочей нагрузки.Их можно объединятьвтранзакции,итранзакция выполняется как единое целое: ошибка даже в одном запросе воспринимается как ошибка всей транзакции целиком. Механизм транзакций устроен так, что даже один запрос, не обернутый явно в команды управления транзакциями (BEGIN и END), также является транзакцией (состоящей из одной команды).
По количеству выполняемых транзакций можно сделать выводы о том, насколько активно используется база данных. Найти необходимую информацию можно в pg_stat_database. Она включает в себя поля xact_commit и xact_rollback, которые показывают количество зафиксированных и оборванных транзакций. Сумма этих полей и показываеттранзакционную активность в базе данных:
2.4. Подключенные клиенты |
45 |
#SELECT datname, xact_commit + xact_rollback AS xacts FROM pg_stat_database
ORDER BY xact_commit + xact_rollback DESC; datname | xacts
----------- |
+ |
--------- |
pgbench |
| 5786340 |
|
postgres |
| |
357301 |
template1 | |
6116 |
|
|
| |
13 |
template0 | |
0 |
|
Втестовом окружении всегодве активно используемые БД: pgbench и postgres.Также естьособая строка с отсутствующим именем базы данных,которая содержит статистику общих объектов системного каталога. Следующим запросом мы можем получить данные из мониторинга:
#rate(postgres_database_xact_commits_total{service_id="primary"} + postgres_database_xact_rollbacks_total{service_id="primary"}[1m])
Запроссчитаетколичествовыполненныхтранзакцийвсекунду,наегоосновеможнополучить график (рис. 2.5), который показывает эту картину в динамике. На нем наглядно видно, что объем выполняемых транзакций в БД pgbench в несколько раз больше,чем в БД postgres.
Рис. 2.5.Транзакционная активность: количество транзакций в секунду
График транзакционной активности полезен для поверхностного анализа и понимания текущейактивностивСУБД,онхорошоподходитвкачествесводногографикадлядежурныхинженеров. Сильные колебания обычно являются признаком изменения количества экземпляров приложений или изменения в объеме рабочей нагрузки, вследствие чего может измениться и использование ресурсов со стороны СУБД.
46 |
Глава 2. Статистика активности |
Подсчет транзакций с помощью pg_stat_statements
Информацию о транзакциях можно получить с помощью pg_stat_statements.query, отслеживая команды начала и завершения транзакций (BEGIN, COMMIT и пр.). Однако у этого способа есть несколько недостатков.Во-первых,должно быть включено отслеживание служебных команд (track_utility =on).Во-вторых,расширение регистрируеттолько прямые вызовы команды ROLLBACK, следовательно, невозможно отслеживать откаты транзакций, произошедшие из-за ошибок. В-третьих, не всегда возможно отследить начало транзакции. Например,если клиент использует \set AUTOCOMMIT off,транзакция будет открываться неявно сразу после первой выполненной команды. Поэтому учет с помощью pg_stat_statements хоть и возможен,но менее удобен.
Статусы завершения сеансов
Нормальная работа сеанса предполагает, что клиент устанавливает соединение с СУБД, отправляет запросы и, когда необходимость в подключении исчезает, закрывает соединение
иотключается. Однако возможно и аномальное поведение, при котором сеанс будет прерван:
•сброс соединения клиентом,СУБД или промежуточным сетевым устройством;
•возникновение ошибки в сеансе,после которой продолжение сеанса невозможно;
•принудительное завершение сеанса по инициативе администратора или СУБД.
Вполне возможны и другие, более экзотические варианты развития событий, но перечисленные выше причины встречаются наиболее часто.Аварийное завершение сеанса может происходить редко и незаметно—если сеанс прервется,СУБД запишет сообщение в журнал,приложение переустановит соединение и работа продолжится. Такое бывает из-за сетевых ошибок, тайм-аутов или потерь пакетов, когда нарушается работа TCP-соединения. Но есть и другая крайность: шквал ошибок, которые невозможно не заметить или игнорировать. Обычно это результат ошибок прикладного уровня, когда завершение сеанса происходит из-за ошибки в приложении. Например, после обрыва сеанса приложение может переустанавливать соединениеивыполнятькодсошибкой,врезультатечегосеанссбрасываетсяивсеповторяетсясновабезостановки.Такоеповедениехорошоописываетсятерминомcrashloop,которыйнепонаслышкезнакомадминистраторамKubernetes.Прикоротком(миллисекунды)интервалемежду ошибками приложение может создать шторм из попыток установки соединений. В лучшем случае это приведет к увеличению нагрузки на CPU на стороне СУБД (создание клиентских процессов обходится недешево). В худшем случае при наличии нескольких экземпляров приложения,которыеведутсебяодинаково,можноисчерпатьлимитподключенийmax_connections и сделать невозможным подключение других приложений к СУБД.
Статистика по статусам сеансов находится в pg_stat_database,получить ее можно следующим образом:
2.4. Подключенные клиенты |
47 |
#SELECT datname, sessions, sessions_abandoned, sessions_fatal, sessions_killed FROM pg_stat_database
WHERE sessions > 0; |
|
|
|
|
|
|
||
datname |
| sessions | sessions_abandoned | sessions_fatal | sessions_killed |
|||||||
---------- |
+ |
---------- |
+ |
-------------------- |
+ |
---------------- |
+ |
----------------- |
postgres | |
1154107 |
| |
0 |
| |
0 |
| |
0 |
|
pgbench |
| |
383947 |
| |
0 |
| |
0 |
| |
0 |
Напомню, что pg_stat_database содержит кумулятивную статистику,поэтому среди значений можно наблюдать большие числа.На что нужно обращать внимание в этой статистике,это наличие аномальных статусов: abandoned, fatal и killed. В данном примере таких сеансов не зафиксировано, и это указывает на то, что на уровне сеансов приложения работают корректно и без ошибок. В этом примере можно обратить внимание на то, что к служебной БД postgres выполненогораздобольшесоединений,чемкприкладнойБДpgbench.Спомощьюследующего PromQL-запроса можно построить график и посмотреть картину во времени:
#sum by (database) ( increase(postgres_database_sessions_total{ service_id="primary", database=~"(postgres|pgbench)" }[1m]))
В данном запросе количество сеансов, находящихся в любых статусах, суммируется по двум интересующим нас БД. Статистика является кумулятивной, и для наглядности изменений во времени стоит применить функцию increase, которая показывает изменение метрики за указанный интервал (в этом примере—одна минута).
На графике (рис. 2.6) видно, что довольно большое количество сеансов — примерно 90 в минуту — устанавливается с БД postgres. Это объясняется рабочей нагрузкой, характерной для экспортера метрик. Экспортер устанавливает несколько сеансов на время сбора статистики,
Рис. 2.6.Частота установления сеансов в минуту к базам данных
48Глава 2. Статистика активности
после чего завершает их. Такое поведение не очень эффективно в плане использования ресурсов, поскольку для каждого сеанса СУБД создает отдельный процесс и выполняет дорогостоящую инициализацию.С этойточки зрения выгодно установить и использовать несколько сеансов на постоянной основе, что является хорошей отправной точкой для оптимизации кода экспортера. Кроме экспортера в тестовом окружении работают прикладные приложения, которые перезапускаются каждые несколько минутс новыми параметрами нагрузки,и это заметно по резким пикам установки сеансов с БД pgbench. На практике реальные приложения могут перезапускаться редко, a установленные ими соединения могут продолжать работать в течение многих десятков минут и даже часов.
Пример из практики. Наличие аномальных статусов обычно является признаком проблемы или указывает на неэффективную работу приложения или окружения. Описываемый случай произошел,когда готовился материал этой главы.
Запрос на получение статусов сеансов показал, что значение в sessions_abandoned составляло 13% от общего числа sessions и продолжало медленно увеличиваться. Это довольно большое значение, и я попытался выяснить причины такого количества оставленных сеансов. После отключения тестовой нагрузки счетчик продолжил расти, и подозрения упали на агента мониторинга. Эта проблема мне хорошо известна: она проявляется, если на стороне приложения не закрыть соединение должным образом.Имея доступ к исходному коду агента,я решил проверить все места,где открываются соединения.Нужно было убедиться,что соединения закрываются после использования,и я обнаружил одно из мест,где этого неделалось,что могло приводить к утечке соединений.
Для подтверждения постоянного характера проблемы я построил график (рис. 2.7) на основе следующего запроса:
#sum by (reason) (increase(postgres_database_sessions_total{ service_id="primary",database="pgbench"
}[1m]))
Рис. 2.7.Частота установления сеансов в минуту с группировкой по статусам
