- •Предисловие
- •Об этой книге
- •Глава 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
- •Предметный указатель
2.3. Источники информации об активности |
35 |
Идентификаторытранзакций и горизонта видимости транзакций. Два идентификатора,указыва-
ющиенаприсвоенныйномертранзакцииbackend_xidитранзакционныйгоризонтвидимости backend_xmin,могутбытьполезны при расследовании причин ненормального увеличения размеров таблиц и индексов из-за неэффективной работы автоочистки. Более подробно случаи использования этой статистики мы рассмотрим в главе 8,посвященной очистке.
Представление pg_locks
Представление pg_locks содержит информацию об удерживаемых блокировках. Оно может рассматриваться как самостоятельное, однако на практике часто используется совместно с pg_stat_activity,и оба представления обогащают итоговый результат.
Каждая строка pg_locks содержит информацию об объекте, на который установлена блокировка или для которого требуется установка блокировки, и о том, кто ее затребовал. Когда несколько процессов пытаются взять блокировку одного и того же объекта, этот объект будетпоказан в представлении несколько раз.При снятии блокировки с объекта информация из представления убирается.Объектами блокировки могут бытьтаблицы,отдельные строки или даже страницы в таблицах, идентификаторы транзакций, общие объекты СУБД. Некоторые действия, требующие блокировки, представлены отдельными объектами, например увеличение файлов таблицы или обновление таких метаданных, как pg_database.datfrozenxid. Также в представлении отображаются рекомендательные блокировки (advisory lock), смысл и назначение которых определяют сами приложения, но нет информации по легким блокировкам (lightweight lock, LWLock), которые работают на более низком уровне для контроля доступа
кслужебным структурам в памяти.
#\d pg_locks
|
|
View "pg_catalog.pg_locks" |
|
|
|
Column |
| |
Type |
| Collation | Nullable | Default |
||
-------------------- |
+ |
-------------------------- |
+----------- |
+---------- |
+--------- |
locktype |
| |
text |
| |
| |
| |
database |
| |
oid |
| |
| |
| |
relation |
| |
oid |
| |
| |
| |
page |
| |
integer |
| |
| |
| |
tuple |
| |
smallint |
| |
| |
| |
virtualxid |
| |
text |
| |
| |
| |
transactionid |
| |
xid |
| |
| |
| |
classid |
| |
oid |
| |
| |
| |
objid |
| |
oid |
| |
| |
| |
objsubid |
| |
smallint |
| |
| |
| |
virtualtransaction | |
text |
| |
| |
| |
|
pid |
| |
integer |
| |
| |
| |
mode |
| |
text |
| |
| |
| |
granted |
| |
boolean |
| |
| |
| |
fastpath |
| |
boolean |
| |
| |
| |
waitstart |
| |
timestamp with time zone | |
| |
| |
|
36Глава 2. Статистика активности
Посмотреть полное описание pg_locks можно с помощью метакоманды \d+ pg_locks, а выше приведено его сокращенное описание. Это представление показывает табличную информацию на основе функции pg_lock_status.
Объект блокировки. С помощью следующего набора полей можно идентифицировать объект, связанный с блокировкой:
•relation,page,tuple—отношение,номер страницы и номер строки внутри страницы;
•virtualxid,transactionid—виртуальный и фактический номера транзакций;
•classid, objid, objsubid — идентификаторы объекта блокировки внутри системного каталога в случае,когда этот объект нереляционный.
Взависимости отобъекта блокировки значения в некоторых полях могутотсутствовать (NULL).
Детали блокировки. Поля с дополнительной информацией играют важную роль в определении процессов,ожидающих получения блокировки:
•locktype—тип блокировки,который позволяет отличать блокировки друг отдруга1;
•database—идентификатор (OID) базы данных,в которой возникла блокировка;
•virtualtransaction — идентификатор виртуальной транзакции, которая удерживает или ждет блокировку;
•pid — идентификатор процесса ОС. Чаще всего это поле используется для соединения с pg_stat_activity и получения такой дополнительной информации, как имя пользователя,время начала запроса или транзакции,текст запроса,маркеры ожидания и т. д.;
•mode — режим блокировки, который позволяет определять совместимость с другими блокировками.Полный список режимов доступен в документации2;
•granted— флаг, указывающий на факт удерживания блокировки (значение true) или ожидания ее получения (значение false);
•waitstart — время перехода в ожидание блокировки. Это поле является единственным источником достоверной информации о том, сколько времени процесс находится в ожидании блокировки. Однако стоит учитывать, что даже после того как началось ожидание блокировки (granted = false),значение поля втечение очень короткого периода можетотсутствовать (NULL);
•fastpath—флаг,указывающийнафактвзятияблокировкичерезинтерфейсfast-path.Этот интерфейс давно объявлен устаревшим, и это поле актуально только в случаях эксплуатации приложений,которые его используют.
Спомощьюдеталей блокировки можно отсеиватьлишние блокировки и фокусироватьсятолько на тех, что напрямую относятся к исследуемой проблеме, например связаны с конкретным сеансом, или имеют определенный тип, или находятся в ожидании дольше допустимого времени. Соединение с pg_stat_activity позволяет получить дополнительную информацию,
1 postgrespro.ru/docs/postgresql/current/monitoring-stats#WAIT-EVENT-LOCK-TABLE 2 postgrespro.ru/docs/postgresql/current/explicit-locking#LOCKING-TABLES
2.3. Источники информации об активности |
37 |
которая будет полезна для анализа и исправления проблемы на стороне прикладных приложений (имя пользователя и приложения,текст запроса).
Особенности pg_stat_activity и pg_locks
У обоих представлений, pg_stat_activity и pg_locks, есть одна важная особенность, которую я привык рассматривать скорее как недостаток. О ней всегда следует помнить при реализации мониторинга на основе этих представлений. Выводимая статистика отражает текущий момент и не является кумулятивной. Данные, взятые из этих представлений, являются снимками того, что происходило в момент обращения к представлениям. Неизвестно, что происходило в интервале между двумя снимками. На практике можно встретить системы, которые обслуживают десятки и сотни тысяч запросов в секунду. В промежутках между снимками можетвозникатьбольшоеколичествократковременныхожиданий,которыенепопадутвснимки и не будут видны в мониторинге, но эти ожидания могут негативно сказываться на времени выполнения запросов. Так, отсутствие информации создает неполную картину о происходящем.Припостроениисистеммониторингаинакоплениистатистикинаосноветакихснимков объективность картины начинает сильно зависеть от частоты опроса статистики. На практике такой опрос выполняется с интервалом в несколько секунд и наиболее часто встречаются значения между 15 и 60 секундами.Нодаже профилирование с частотой 1–10 миллисекунд не гарантирует полноты картины, к тому же добавляет накладные расходы на выполнение самого профилирования. Резюмируем: глядя на графики, построенные на основе представлений pg_stat_activity или pg_locks, вы должны помнить об этой особенности. Некоторые другие представления устроены подобным образом, и в дальнейшем, рассматривая их, я буду отмечать это отдельно.
Представление pg_stat_database
Каждая строка представления pg_stat_database содержит статистику об использовании конкретной базы данных. Также в представлении есть отдельная строка, которая содержит статистику по разделяемым, общим для всех баз объектам (часть из них принадлежат так называемому системному каталогу). Представление основано на семействе функций с префиксом pg_stat_get_db_, которые принимают в качестве аргумента идентификатор БД и возвращают одну метрику. Полное описание представления можно получить с помощью метакоманды \d+ pg_stat_database. Часть полей этого представления можно отнести к статистике клиентских подключений,что может помочь при мониторинге активности СУБД.
Представление хоть и содержит информацию о базах данных, однако некоторые сведения можно рассматривать в контексте, связанном с клиентами и их сеансами. С помощью этой информации можно отслеживать и количество подключенных клиентов, и то, насколько нормально приложения работают с СУБД.Воспользоваться можно следующими полями:
•numbackends — количество клиентских процессов, подключенных к БД. В строке со статистикой по разделяемым объектам значение будет отсутствовать (NULL). Это единственное
38 |
Глава 2. Статистика активности |
поле в представлении, которое показывает текущее значение. Все остальные поля содержат кумулятивную статистику за определенный период;
•xact_commit—количествотранзакций,завершившихсяфиксацией(COMMIT).Счетчиктакже учитывает успешное выполнение одиночных запросов в рамках неявных транзакций;
•xact_rollback—количество транзакций,завершившихся обрывом (ROLLBACK),в том числе по причине ошибок;
•sessions_abandoned — количество сеансов, принудительно завершенных по причине того, что соединение оставлено клиентом.Это может указывать на ситуации,когда клиентское приложение забывает о соединении и не закрывает его как положено (graceful close).Другой причиной могут быть сетевые проблемы, такие как ошибки передачи и потери пакетов,приводящие к нарушению работы TCP-сеансов;
•sessions_fatal — количество сеансов, которые были принудительно завершены по причине возникновения фатальных ошибок и невозможности продолжения работы. Такие ошибки могут происходить во время выполнения запросов или вызываться исключительными ситуациями на стороне сервера при взаимодействии между клиентом и сервером. В таком случае сервер не может продолжить сеанс и завершает его. Примером такого сценария может быть завершение сеанса из-за превышения тайм-аута, настроенного пара-
метром idle_in_transaction_session_timeout;
•sessions_killed — количество сеансов, которые были принудительно завершены административным способом. Такое завершение сеанса может быть инициировано функцией pg_terminate_backend или самой СУБД, например при выключении или перезапуске сервера;
•sessions — суммарное количество сеансов, установленных с БД. Значение поля указывает на общее число установленных сеансов независимо от статуса их завершения, то есть включает в себя все значения и по остальным возможным статусам.
Начало и завершение сеанса обычно происходит по инициативе клиента. Часть рассматриваемых полей как раз указываютна количество сеансов,завершение которых было инициированосерверомСУБД.Завершениесеансов,такимобразом,внекоторыхситуацияхможносчитать ненормальным. В процессе сеанса клиент отправляет отдельные команды или может объединять их в транзакции. Эти команды формируют рабочую нагрузку, и по полям xact_commit и xact_rollback можно в количественном выражении вычислить величину нагрузки в СУБД.
Другаяполезнаяинформацияоработесеансовотноситсякихпродолжительностивразныхсостояниях.Речьотехсостояниях,чтокороткоупоминалисьприрассмотренииpg_stat_activity и более подробно рассмотрены чуть дальше. Однако набор полей является неполным, и часть информации придется вычислить с помощью простых арифметических операций. Нас интересуют следующие поля:
•session_time—суммарное время,проведенное всеми сеансами.Учетвремени имеетнекоторую особенность: время увеличивается только при переходе между состояниями. Поэтому можно ожидать появления больших скачков при наличии сеансов, которые могут
