F.51. pg_trace#
F.51. pg_trace #
Отслеживание запросов в реальном времени для Tantor SE-1C
F.51.1. Обзор #
pg_trace
- это библиотека трассировки, которая позволяет
отслеживать выполняемые запросы в реальном времени, включая их ресурсы,
время выполнения и план запроса.
Особенности
Фильтрация запросов с использованием пользовательских условий
Встроенный тайм-аут трассировки, после которого она будет отключена
Поддержка нескольких одновременных клиентов, прослушивающих трассировки
Несколько собранных статистик о запросе: ресурсы, время, план запроса
F.51.2. Начало работы #
Добавьте расширение в shared_preload_libraries
в
postgresql.conf
:
shared_preload_libraries = 'pg_trace'
Создайте расширение и начните трассировку
CREATE EXTENSION pg_trace; SELECT pg_trace_start();
Подключиться к сокету. Т.е. используя nc
:
nc -U /tmp/pg_trace.sock
Выполните несколько запросов:
SELECT 1;
Вы увидите вывод, подобный этому:
{"traceid":0,"queryid":6865378226349601843,"dbid":5,"userid":10,"tuplescount":1,"start_time":1733221222489,"end_time":1733221222489,"total_time":0.00739,"startup_time":0,"sys_time":0,"user_time":0,"rows":1,"shared_blks_hit":0,"shared_blks_read":0,"shared_blks_written":0,"shared_blks_dirtied":0,"local_blks_hit":0,"local_blks_read":0,"local_blks_written":0,"local_blks_dirtied":0,"shared_blk_read_time":0,"shared_blk_write_time":0,"local_blk_read_time":0,"local_blk_write_time":0,"temp_blk_read_time":0,"temp_blk_write_time":0,"wal_records":0,"wal_fpi":0,"wal_bytes":0,"query":"select 1;"}
F.51.3. Функциональность #
F.51.3.1. Управление трассировкой #
Чтобы начать трассировку, используйте функцию
pg_trace_start()
.
CREATE FUNCTION pg_trace_start( backend_pid int DEFAULT NULL, user_id oid DEFAULT NULL, database_id oid DEFAULT NULL, duration interval DEFAULT NULL, query_like text DEFAULT NULL, plan boolean DEFAULT FALSE, timeout interval DEFAULT NULL ) RETURNS boolean; -- example SELECT pg_trace_start( user_id := 123, query_like := 'SELECT *%', plan := TRUE, timeout := interval '1 hour' );
Эта функция начинает новую сессию трассировки. Она принимает аргументы:
Фильтрация атрибутов, если
NULL
фильтр не применяется:backend_pid
- запрос выполнен на этом сервереuser_id
- запрос выполнен этим эффективным пользователемdatabase_id
- запрос выполнен в этой базе данныхduration
- запрос выполнялся дольше, чем указаноquery_like
- запрос должен соответствовать шаблону (используяLIKE
)
plan
- включить план запроса в вывод трассировкиtimeout
- переопределить тайм-аут трассировки по умолчанию с указанным интервалом
Возвращает boolean
- трассировка была включена, когда
выполнялась функция.
Чтобы остановить трассировку сессии, выполните pg_trace_stop()
:
CREATE FUNCTION pg_trace_stop() RETURNS boolean; SELECT pg_trace_stop();
Эта функция принудительно отключает трассировку. Возвращает
boolean
- трассировка была включена при запуске функции.
Чтобы проверить, включена ли трассировка, используйте
функцию pg_trace_enabled
:
CREATE FUNCTION pg_trace_enabled() RETURN boolean; SELECT pg_trace_enabled();
F.51.3.2. Наблюдаемость #
Для отправки трассировок расширение использует фоновый рабочий процесс, который здесь называется сервером. Сервер собирает некоторые метрики и предоставляет их с помощью SQL функций:
Общее количество клиентов, подключенных к серверу
CREATE FUNCTION @extschema@.pg_trace_metrics_clients_accepted() RETURNS bigint;
Общее количество клиентов, отключенных от сервера
CREATE FUNCTION @extschema@.pg_trace_metrics_clients_disconnected() RETURNS bigint;
Общее количество раз, когда WaitEventSet был воссоздан
CREATE FUNCTION @extschema@.pg_trace_metrics_wes_recreations() RETURNS bigint;
Общее количество собранных трассировок
CREATE FUNCTION @extschema@.pg_trace_metrics_traces_collected() RETURNS bigint;
Общее количество трассировок было отклонено из-за нехватки свободного места
CREATE FUNCTION @extschema@.pg_trace_metrics_traces_declined() RETURNS bigint;
Общее количество байт, отправленных всем клиентам через сокет
CREATE FUNCTION @extschema@.pg_trace_metrics_send_bytes() RETURNS bigint;
Общее количество случаев, когда отправка данных через сокет вернула ошибку
CREATE FUNCTION @extschema@.pg_trace_metrics_send_errors() RETURNS bigint;
Описание
pg_trace_metrics_wes_recreations
см. ниже
F.51.4. Клиент-серверный протокол #
Взаимодействие между сервером (фоновым рабочим процессом) и клиентом (приложением, читающим трассировки) настроено в клиент/серверной манере.
Клиент подключается к серверному UNIX-сокету (он должен знать его расположение). После подключения клиент начнет получать сообщения. Каждое сообщение представляет собой один trace и содержит 2 поля:
Длина | Трассировка |
---|---|
4 байта | N байт |
Length
- длина поля Trace
.
Это хранится как сериализованное целое число в формате little-endian.
Trace
- ASCII кодированное JSON представление
объекта Trace.
Схема JSON сообщения:
Ключ | Тип | Описание |
---|---|---|
queryid
|
number
| ID запроса |
dbid
|
number
| OID базы данных |
userid
|
number
| OID пользователя |
tuplescount
|
number
| Общее количество кортежей, обработанных запросом |
start_time
|
number
| UNIX метка времени начала выполнения запроса |
end_time
|
number
| UNIX метка времени окончания выполнения запроса |
total_time
|
number
| количество времени, в течение которого выполнялся запрос, в секундах |
startup_time
|
number
| время запуска запроса |
startup_time
|
number
| общее время выполнения запроса |
sys_time
|
number
| количество времени, которое запрос провел в пространстве ядра |
user_time
|
number
| время, проведенное запросом в пользовательском пространстве |
rows
|
number
| Общее количество строк, извлеченных или затронутых запросом |
shared_blks_hit
|
number
| Общее количество попаданий в кэш общих блоков для данного выражения |
shared_blks_read
|
number
| Общее количество общих блоков, прочитанных оператором |
shared_blks_written
|
number
| Общее количество общих блоков, записанных оператором |
shared_blks_dirtied
|
number
| Общее количество общих блоков, измененных оператором |
local_blks_hit
|
number
| Общее количество попаданий в локальный кэш блоков по оператору |
local_blks_read
|
number
| Общее количество локальных блоков, прочитанных оператором |
local_blks_written
|
number
| Общее количество локальных блоков, записанных оператором |
local_blks_dirtied
|
number
| Общее количество локальных блоков, измененных оператором |
local_blks_dirtied
|
number
| Общее количество локальных блоков, измененных оператором |
shared_blk_read_time
|
number
| Общее время, затраченное оператором на чтение общих блоков данных файла, в миллисекундах |
shared_blk_write_time
|
число
| Общее время, затраченное оператором на запись общих блоков данных файла, в миллисекундах |
local_blk_read_time
|
number
| Общее время, затраченное оператором на чтение локальных блоков данных файла, в миллисекундах |
local_blk_write_time
|
number
| Общее время, затраченное оператором на запись локальных блоков данных в файл, в миллисекундах |
temp_blk_read_time
|
number
| Общее время, затраченное оператором на чтение блоков временного файла, в миллисекундах |
temp_blk_write_time
|
number
| Общее время, затраченное оператором на запись блоков временного файла, в миллисекундах |
wal_records
|
number
| Общее количество записей WAL, созданных оператором |
wal_fpi
|
number
| Общее количество полных изображений страниц WAL, сгенерированных оператором |
wal_bytes
|
number
| Общее количество WAL, сгенерированного оператором, в байтах |
query
|
string
| Строка запроса |
plan
|
plan object
| План запроса в формате EXPLAIN JSON |
jit_functions
|
number
| Количество сгенерированных JIT функций |
jit_generation_time
|
number
| Накопленное время на генерацию кода с использованием JIT |
jit_optimization_time
|
number
| Накопленное время для генерации кода с использованием JIT |
jit_inlining_time
|
number
| Накопленное время, использованное для инлайнинга JIT-кода |
jit_emission_time
|
number
| Накопленное время для генерации JIT-кода |
Многие поля содержат информацию о времени. В этой схеме вся информация о времени предоставляется в виде UNIX временной метки.
План предоставляется в виде JSON-объекта, сгенерированного с помощью EXPLAIN.
F.51.5. Конфигурация #
pg_trace.max_clients
- максимальное количество клиентов,
которые могут обрабатываться одновременно.
pg_trace.trace_plan_mem
- объем памяти, используемой
для хранения плана запроса в текстовом представлении. Указывается как объем памяти
с суффиксом размера. Например, 8 kB
. По умолчанию установлено
на 16 kB.
Примечание
Этот параметр повлияет на размер результата одной записи Trace. Таким образом, изменение этого параметра повлияет на другие.
pg_trace.traces_mem
- объем памяти для
выделения под трассировки в серверном фоновом процессе. Указывается как
объем памяти с суффиксом размера. Например, 128 MB
. По
умолчанию устанавливается объем памяти для хранения ровно 5000 трассировок.
pg_trace.shm_queue_mem
- объем памяти, выделяемой в общей памяти для буфера трассировок. Указывается как объем памяти с суффиксом размера. Например, 32 MB
. По умолчанию установлено на объем памяти, достаточный для хранения ровно 32 трассировок.
Примечание
Если вы укажете объем памяти меньше, чем размер 1
Trace, вы получите ошибку
.
traces_mem
и shm_queue_mem
зависят от настройки trace_plan_mem
.
pg_trace.unix_socket_path
- путь к unix сокету
для сервера. Если сокет уже существует, он будет удален и будет создан новый
сокет. По умолчанию,
/tmp/pg_trace.sock
.
pg_trace.trace_timeout
- тайм-аут по умолчанию для
сеанса трассировки, после которого сеанс трассировки будет автоматически
отключен. Это значение используется, если аргумент timeout
в pg_trace_start
не установлен. Указывается как
время с суффиксом времени. Например, 1h
. По умолчанию, 10
минут.
pg_trace.update_delay
- время ожидания перед началом обработки трассировки из очереди общей памяти фоновым рабочим процессом. Это время может дать бэкэндам шанс записать больше трассировок в очередь, прежде чем фоновый рабочий процесс возьмет эксклюзивную блокировку. По умолчанию, 0
- без задержки.
pg_trace.plan_format
- формат плана, который передается, когда 'plan' был запрошен при запуске трассировки сессии. Допустимые значения: text
, json
, yaml
, xml
. Если запрашивается json
, будет использован объект плана в формате JSON, в противном случае (для других форматов) он будет представлен как строка плана (возможно, экранированная для JSON). По умолчанию используется формат text
.
Параметры trace_timeout
,
update_delay
и plan_format
могут быть изменены с помощью обновления файла конфигурации с
отправкой SIGHUP
. Все остальные не могут быть изменены
после запуска postgres - необходимо перезапустить сервер.
F.51.6. Как это работает #
Терминология
Сервер - фоновый рабочий процесс
Клиент - пользователь, который подключается к сокету и прослушивает трассировки
Backend - сервер, который выполняет запросы и передает трассировки фоновому рабочему процессу
Общая архитектура и принципы работы:
----------------- Trace format ---------------- +---------------------+ | Instrumentation | | Timings | | Resources | +---------------------+ | Query plan | `pg_trace.plan_max` +---------------------+ ---------------- Architecture ---------------- +---------+ +---------+ +---------+ | backend | | backend | | backend | +---------+ +---------+ +---------+ \ | / +--------------------+--------------------+ | filtering | | V `pg_trace.shm_queue_max` +---------------------+ buffer +---+---+---+ | shared memory queue |--------------------| X | | | +---------------------+ +---+---+---+ | | | V `pg_trace.traces_mem` +---------------------+ ring buffer +---+---+---+---+---+ | background worker |---------------| X | X | X | X | | +---------------------+ +---+---+---+---+---+ | | | +------------------+------------------+ / | \ | | | V V V O O O /|\ /|\ /|\ / \ / \ / \ `pg_trace.max_clients`
Когда запрос выполняется и проходит все переданные фильтры, он отправляется
в фоновый рабочий процесс, используя очередь общей памяти. Он содержит буфер
размером pg_trace.shm_queue_max
.
После этого фоновый рабочий копирует все трассировки из буфера очереди shm
в свой собственный буфер. Трассировки хранятся в кольцевом буфере. Он
выделяется при запуске сервера с размером
pg_trace.traces_mem
. Текущая реализация
позволяет всем операциям (освобождение, поиск, вставка и т.д.) иметь
сложность O(1), так что не стесняйтесь увеличивать этот параметр.
Когда добавляются новые трассировки, они отправляются клиентам. Максимальное количество
клиентов, которые могут обрабатываться одновременно, устанавливается с помощью
параметра pg_trace.max_clients
.
Сервер реализован с использованием неблокирующих сокетов. Он использует
WaitEventSet
функциональность PostgreSQL для
реализации этого, так что все платформы должны поддерживаться. Также это
означает, что для новых клиентов используется тот же фоновый рабочий процесс для
отправки данных - не стесняйтесь увеличивать количество максимальных клиентов.
F.51.7. Известные проблемы #
F.51.7.1. Воссоздание WaitEventSet #
Для отслеживания асинхронных запросов используется WaitEventSet
.
Когда новый клиент подключается, его сокет добавляется в
этот набор.
Когда клиент отключается, нам нужно отключить его отслеживание. К сожалению, в настоящее время нет способа удалить клиента из набора и добавить нового позже, поэтому мы просто прекращаем его отслеживание. Рано или поздно свободное место закончится.
Чтобы справиться с этой ситуацией, этот WaitEventSet пересоздается. Эта операция не бесплатна, потому что нам нужно закрыть старый файловый дескриптор, создать новый и пройти через всех клиентов и отфильтровать активных.
Количество раз, когда нам нужно воссоздать
WaitEventSet
, можно уменьшить, увеличив
настройку pg_trace.max_clients
.
Метрика функция
pg_trace_metrics_wes_recreations
возвращает
количество раз, когда этот WaitEventSet был воссоздан.
F.51.7.2. Состояние гонки #
Функции pg_trace_start
и
pg_trace_stop
могут использоваться одновременно.
Состояние обновляется атомарно (в блокировке), но эти функции могут работать одновременно. Пользователь должен сам отслеживать их использование.
F.51.7.3. Привилегии #
По умолчанию, pg_trace_start
и
pg_trace_stop
создаются без какой-либо
проверки привилегий. Разрешение использования этих функций всеми
может привести к утечкам безопасности и ухудшению производительности.
Чтобы исправить это, измените привилегии доступа:
REVOKE EXECUTE ON FUNCTION pg_trace_start FROM public; REVOKE EXECUTE ON FUNCTION pg_trace_stop FROM public; GRANT EXECUTE ON FUNCTION pg_trace_start TO superuser; GRANT EXECUTE ON FUNCTION pg_trace_stop TO superuser;
F.51.7.4. Память плана #
Объем памяти для хранения плана запроса устанавливается с помощью
pg_trace.trace_plan_mem
и используется для хранения
сериализованного представления плана запроса для передачи на сервер. Он
фиксирован, поэтому иногда это может быть меньше размера результата
сериализованного плана. В таких случаях план не устанавливается в
объекте JSON трассировки.
Т.е. pg_trace.trace_plan_mem
установлено в 1 кБ, но
общий сериализованный размер плана запроса составляет 1,5 кБ. В этом случае
план не устанавливается в выходном JSON.