Механизмы
мониторинга
баз данных:
взгляд изнутри
Дмитрий Еманов
Firebird Project
Чего не будет в этом докладе

Как использовать top / iostat / perf / etc

Сравнения Zabbix / Cacti / Graphite / whatever

Красивых графиков с визуализацией ахтунгов в
продакшне с разных ракурсов

Нюансов интеграции с StatsD, CollectD или PerfMon
О чем будем говорить

Какая информация нужна DBA/DevOps от СУБД

Какими способами СУБД может ее предоставить

Какие тут присутствуют подводные камни

Немного поговорим про метрики

Поглядим на MySQL, PostgreSQL, Firebird

Байки из жизни: собственный опыт
Что имеет смысл мониторить

Доступность и целостность

Кто и что делает

Качественные и количественные данные

Пиковые и предельные ситуации

Системные и прикладные ошибки
Доступность и целостность

Доступность — извне, на разных уровнях

Целостность — изнутри

Критические ошибки в логах СУБД

Опционально: контрольные суммы

Возможность онлайн-валидации физической структуры
Кто и что делает

Активность (а также псевдо-активность) юзеров

Привязка к коннектам, транзакциям, SQL-запросам

Идентификация клиентов

Привязка к процессам / потокам ОС

Фоновые задачи СУБД
Идентификация клиентов

С какого хоста пришел запрос:
host/IP, MAC, протокол

С какого приложения пришел запрос:
port, PID, pathname, tag

Каким API пользовался клиент:
версия клиентской либы, версия протокола
Какая информация бывает
Executor Statistics
manager
Log manager
Рантайм-
статистика
Журналы
Какая информация бывает

Снэпшот — что происходит прямо сейчас
(на момент обращения), текущие значения метрик,
иногда пиковые значения метрик

История — полная или частичная хронология
событий мониторинга
Какая информация бывает

Снэпшот — требует периодического опроса;
может пропускать события; высокочастотный опрос
может сильно нагружать СУБД

История — при злоупотреблении нагружает СУБД;
быстро забивает дисковое пространство;
надо четко понимать, что именно хотим знать
Какая информация бывает

Штатные логи СУБД — история

Специальные утилиты — обычно снэпшот

SQL интерфейс — снэпшот

Через штатный API — снэпшот

Через низкоуровневую интеграцию (плагины) —
возможны варианты
Метрики

Обычно это текущие значения счетчиков

С одной стороны, считать надо много событий

Лучше перебдеть, чем недобдеть (с)

Но их детализация может стоить недешево
Детализация метрик

Только для сессии?
Или еще и для каждой транзакции?
Или еще и для каждого запроса?
А может, еще ниже уровнем?
Пытаемся считать на разных уровнях

Вот так — очень быстро
session→stats→record_backouts++;

Вот так — не очень быстро
query→stats→record_backouts++;
query→txn→stats→record_backouts++;
query→txn→session→stats→record_backouts++;
query→txn→session→db→stats→record_backouts++;
Пытаемся считать на разных уровнях

Но некоторые уровни могут и отсутствовать,
это надо проверять!

Вот так — совсем тормоза :-(
if (object)
object→stats→record_backouts++;
// и еще три раза
Как мы выкручиваемся
// Thread specific context data
struct Context : public ThreadData
{
Database* database;
Attachment* attachment;
Transaction* transaction;
Request* request;
RuntimeStatistics *reqStat, *traStat, *attStat, *dbbStat;
}
Как мы выкручиваемся
explicit Context(ISC_STATUS* status)
: ThreadData(ThreadData::tddDBB),
database(NULL), attachment(NULL),
transaction(NULL), request(NULL)
{
reqStat = traStat = attStat = dbbStat =
RuntimeStatistics::getDummy();
}
Как мы выкручиваемся
void setAttachment(Attachment* val)
{
attachment = val;
attStat = val ? &val->att_stats : RuntimeStatistics::getDummy();
}
void bumpStats(const RuntimeStatistics::StatType index)
{
reqStat->bumpValue(index);
traStat->bumpValue(index);
attStat->bumpValue(index);
dbbStat->bumpValue(index);
}
Детализация метрик

Глобальные счетчики — это просто, но неинтересно

Кое-что надо бы потаблично
Еще для индексов
А если помечтать, то...
… и тут Остапа понесло (с)
Детализация метрик

Счетчик надо сначала найти!

Хэш-таблица?
Сортированный массив?
Или, может, бинарное дерево?

Это все временные затраты, их надо оценивать
Детализация метрик
#if defined(REL_COUNTS_TREE)
typedef Firebird::BePlusTree<RelationCounts, ULONG,
Firebird::MemoryPool, RelationCounts> RelCounters;
#elif defined(REL_COUNTS_PTR)
typedef Firebird::PointersArray<RelationCounts,
Firebird::EmptyStorage<RelationCounts>,
ULONG, RelationCounts> RelCounters;
#else // sorted array
typedef Firebird::SortedArray<RelationCounts,
Firebird::EmptyStorage<RelationCounts>,
ULONG, RelationCounts> RelCounters;
#endif
Мониторинг ожиданий

I/O, блокировки разных видов

Кто, кого и на чем ждет

Интересен также контекст

Графы ожиданий, дэдлоки
Мониторинг ожиданий

I/O, блокировки разных видов

Кто, кого и на чем ждет

Интересен также контекст

Графы ожиданий, дэдлоки

Но самое интересное — время ожидания

Однако, тут могут быть сюрпризы!
Метрики: советы

Больше метрик, хороших и разных

Детализация стоит дорого, трижды подумайте над
реализацией (и надо ли оно вам вообще)

Если накладные расходы велики —
можно использовать отложенную запись

Самую тяжелую статистику имеет смысл
делать опциональной
Как выдавать данные наружу

Регулярно обновлять состояние и счетчики
в общей памяти — накладные расходы,
зато возможен высокочастотный мониторинг

Предоставлять состояние по запросу, метрики считать
локально и предоставлять также по запросу —
снэпшот слегка отстает, больше задержки при запросах
к мониторингу
Снэпшот-мониторинг в MySQL

performance_schema

Не такой уж и снэпшот

Можно включать/выключать (требуется перезапуск)

Настраивать можно «на лету»

Помимо счетчиков содержит также *_summary
Снэпшот-мониторинг в PostgreSQL

Statistics collector

Включать/выключать можно «на лету», по группам

Динамические представления pg_stat_* и pg_locks

Обновляется периодически

Снэпшот на время жизни транзакции
Наш опыт: снэпшот-мониторинг в Firebird

Виртуальные таблицы мониторинга

Метрики (локально) считаем всегда,
время замеряем опционально

Информация собирается по запросу

Снэпшот на время жизни транзакции
Наш опыт: снэпшот-мониторинг в Firebird

MON$DATABASE

MON$ATTACHMENTS

MON$TRANSACTIONS

MON$STATEMENTS

MON$CALL_STACK
+

MON$*_STATS

MON$*_USAGE
Наш опыт: снэпшот-мониторинг в Firebird

MON$DATABASE

MON$ATTACHMENTS

MON$TRANSACTIONS

MON$STATEMENTS

MON$CALL_STACK
+

MON$*_STATS

MON$*_USAGE
Считаются для каждого
объекта выше
Наш опыт: снэпшот-мониторинг в Firebird

MON$DATABASE

MON$ATTACHMENTS

MON$TRANSACTIONS

MON$STATEMENTS

MON$CALL_STACK
+

MON$*_STATS

MON$*_USAGE
Считаются для каждого
объекта выше
Агрегируются
снизу вверх
Логирование

Критические ошибки

Алерты — логические ошибки и пиковые ситуации
(медленные запросы, временные файлы)

Интерактивная трассировка

Аудит — постоянное логирование
Логирование в MySQL

Error log

General query log

Slow query log

Audit API + плагины
Логирование в PostgreSQL

Разные варианты — stderr / syslog / eventlog / файл

Есть функционал slow query log — через
log_min_duration_statement

Кастомизация логируемых запросов, умеет писать
долгие блокировки, временные файлы и т.п.

Динамическая трассировка для DTrace / SystemCap
(требует компиляции c --enable-dtrace)
Наш опыт: логирование в Firebird

Trace API + плагины

Системный аудит — управляется ядром, настраивается
конфигом, пишется в лог на диске (по умолчанию)
с ротацией (архивированием)

Пользовательская трассировка — управляется юзером
(start-pause-resume-stop), конфиг задается в рантайме,
лог пишется во временные файлы и удаляется по мере
вычитывания клиентом
Наш опыт: логирование в Firebird

Везде логируем ID объектов

Большинство событий спаренные — начало и конец

По завершении можем выдавать статистику — время
выполнения и детализированные метрики

Есть функционал slow query log — через time_threshold

Дополнительная кастомизация — через include/exclude
фильтры (regexp)
Наш опыт: логирование в Firebird
# трассируем медленные запросы
database = myslowdb
{
log_statement_finish = true
print_perf = true
time_threshold = 10000 # 10 seconds
}
# трассируем изменения метаданных
database = mycooldb
{
log_statement_start = true
include_filter = %(CREATE|ALTER|DROP)%
}
В реальной жизни надо сочетать

В логах — только алерты или подробно

От этого зависит частота снэпшот-мониторинга

Совсем интересно становится,
если их можно связать вместе
Вопросы?
dimitr@firebirdsql.org

Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird Project)

  • 1.
  • 2.
    Чего не будетв этом докладе  Как использовать top / iostat / perf / etc  Сравнения Zabbix / Cacti / Graphite / whatever  Красивых графиков с визуализацией ахтунгов в продакшне с разных ракурсов  Нюансов интеграции с StatsD, CollectD или PerfMon
  • 3.
    О чем будемговорить  Какая информация нужна DBA/DevOps от СУБД  Какими способами СУБД может ее предоставить  Какие тут присутствуют подводные камни  Немного поговорим про метрики  Поглядим на MySQL, PostgreSQL, Firebird  Байки из жизни: собственный опыт
  • 4.
    Что имеет смыслмониторить  Доступность и целостность  Кто и что делает  Качественные и количественные данные  Пиковые и предельные ситуации  Системные и прикладные ошибки
  • 5.
    Доступность и целостность  Доступность— извне, на разных уровнях  Целостность — изнутри  Критические ошибки в логах СУБД  Опционально: контрольные суммы  Возможность онлайн-валидации физической структуры
  • 6.
    Кто и чтоделает  Активность (а также псевдо-активность) юзеров  Привязка к коннектам, транзакциям, SQL-запросам  Идентификация клиентов  Привязка к процессам / потокам ОС  Фоновые задачи СУБД
  • 7.
    Идентификация клиентов  С какогохоста пришел запрос: host/IP, MAC, протокол  С какого приложения пришел запрос: port, PID, pathname, tag  Каким API пользовался клиент: версия клиентской либы, версия протокола
  • 8.
    Какая информация бывает ExecutorStatistics manager Log manager Рантайм- статистика Журналы
  • 9.
    Какая информация бывает  Снэпшот— что происходит прямо сейчас (на момент обращения), текущие значения метрик, иногда пиковые значения метрик  История — полная или частичная хронология событий мониторинга
  • 10.
    Какая информация бывает  Снэпшот— требует периодического опроса; может пропускать события; высокочастотный опрос может сильно нагружать СУБД  История — при злоупотреблении нагружает СУБД; быстро забивает дисковое пространство; надо четко понимать, что именно хотим знать
  • 11.
    Какая информация бывает  Штатныелоги СУБД — история  Специальные утилиты — обычно снэпшот  SQL интерфейс — снэпшот  Через штатный API — снэпшот  Через низкоуровневую интеграцию (плагины) — возможны варианты
  • 12.
    Метрики  Обычно это текущиезначения счетчиков  С одной стороны, считать надо много событий  Лучше перебдеть, чем недобдеть (с)  Но их детализация может стоить недешево
  • 13.
    Детализация метрик  Только длясессии? Или еще и для каждой транзакции? Или еще и для каждого запроса? А может, еще ниже уровнем?
  • 15.
    Пытаемся считать наразных уровнях  Вот так — очень быстро session→stats→record_backouts++;  Вот так — не очень быстро query→stats→record_backouts++; query→txn→stats→record_backouts++; query→txn→session→stats→record_backouts++; query→txn→session→db→stats→record_backouts++;
  • 16.
    Пытаемся считать наразных уровнях  Но некоторые уровни могут и отсутствовать, это надо проверять!  Вот так — совсем тормоза :-( if (object) object→stats→record_backouts++; // и еще три раза
  • 17.
    Как мы выкручиваемся //Thread specific context data struct Context : public ThreadData { Database* database; Attachment* attachment; Transaction* transaction; Request* request; RuntimeStatistics *reqStat, *traStat, *attStat, *dbbStat; }
  • 18.
    Как мы выкручиваемся explicitContext(ISC_STATUS* status) : ThreadData(ThreadData::tddDBB), database(NULL), attachment(NULL), transaction(NULL), request(NULL) { reqStat = traStat = attStat = dbbStat = RuntimeStatistics::getDummy(); }
  • 19.
    Как мы выкручиваемся voidsetAttachment(Attachment* val) { attachment = val; attStat = val ? &val->att_stats : RuntimeStatistics::getDummy(); } void bumpStats(const RuntimeStatistics::StatType index) { reqStat->bumpValue(index); traStat->bumpValue(index); attStat->bumpValue(index); dbbStat->bumpValue(index); }
  • 20.
    Детализация метрик  Глобальные счетчики— это просто, но неинтересно  Кое-что надо бы потаблично Еще для индексов А если помечтать, то... … и тут Остапа понесло (с)
  • 21.
    Детализация метрик  Счетчик надосначала найти!  Хэш-таблица? Сортированный массив? Или, может, бинарное дерево?  Это все временные затраты, их надо оценивать
  • 22.
    Детализация метрик #if defined(REL_COUNTS_TREE) typedefFirebird::BePlusTree<RelationCounts, ULONG, Firebird::MemoryPool, RelationCounts> RelCounters; #elif defined(REL_COUNTS_PTR) typedef Firebird::PointersArray<RelationCounts, Firebird::EmptyStorage<RelationCounts>, ULONG, RelationCounts> RelCounters; #else // sorted array typedef Firebird::SortedArray<RelationCounts, Firebird::EmptyStorage<RelationCounts>, ULONG, RelationCounts> RelCounters; #endif
  • 23.
    Мониторинг ожиданий  I/O, блокировкиразных видов  Кто, кого и на чем ждет  Интересен также контекст  Графы ожиданий, дэдлоки
  • 24.
    Мониторинг ожиданий  I/O, блокировкиразных видов  Кто, кого и на чем ждет  Интересен также контекст  Графы ожиданий, дэдлоки  Но самое интересное — время ожидания  Однако, тут могут быть сюрпризы!
  • 25.
    Метрики: советы  Больше метрик,хороших и разных  Детализация стоит дорого, трижды подумайте над реализацией (и надо ли оно вам вообще)  Если накладные расходы велики — можно использовать отложенную запись  Самую тяжелую статистику имеет смысл делать опциональной
  • 26.
    Как выдавать данныенаружу  Регулярно обновлять состояние и счетчики в общей памяти — накладные расходы, зато возможен высокочастотный мониторинг  Предоставлять состояние по запросу, метрики считать локально и предоставлять также по запросу — снэпшот слегка отстает, больше задержки при запросах к мониторингу
  • 27.
    Снэпшот-мониторинг в MySQL  performance_schema  Нетакой уж и снэпшот  Можно включать/выключать (требуется перезапуск)  Настраивать можно «на лету»  Помимо счетчиков содержит также *_summary
  • 28.
    Снэпшот-мониторинг в PostgreSQL  Statisticscollector  Включать/выключать можно «на лету», по группам  Динамические представления pg_stat_* и pg_locks  Обновляется периодически  Снэпшот на время жизни транзакции
  • 29.
    Наш опыт: снэпшот-мониторингв Firebird  Виртуальные таблицы мониторинга  Метрики (локально) считаем всегда, время замеряем опционально  Информация собирается по запросу  Снэпшот на время жизни транзакции
  • 30.
    Наш опыт: снэпшот-мониторингв Firebird  MON$DATABASE  MON$ATTACHMENTS  MON$TRANSACTIONS  MON$STATEMENTS  MON$CALL_STACK +  MON$*_STATS  MON$*_USAGE
  • 31.
    Наш опыт: снэпшот-мониторингв Firebird  MON$DATABASE  MON$ATTACHMENTS  MON$TRANSACTIONS  MON$STATEMENTS  MON$CALL_STACK +  MON$*_STATS  MON$*_USAGE Считаются для каждого объекта выше
  • 32.
    Наш опыт: снэпшот-мониторингв Firebird  MON$DATABASE  MON$ATTACHMENTS  MON$TRANSACTIONS  MON$STATEMENTS  MON$CALL_STACK +  MON$*_STATS  MON$*_USAGE Считаются для каждого объекта выше Агрегируются снизу вверх
  • 33.
    Логирование  Критические ошибки  Алерты —логические ошибки и пиковые ситуации (медленные запросы, временные файлы)  Интерактивная трассировка  Аудит — постоянное логирование
  • 34.
    Логирование в MySQL  Errorlog  General query log  Slow query log  Audit API + плагины
  • 35.
    Логирование в PostgreSQL  Разныеварианты — stderr / syslog / eventlog / файл  Есть функционал slow query log — через log_min_duration_statement  Кастомизация логируемых запросов, умеет писать долгие блокировки, временные файлы и т.п.  Динамическая трассировка для DTrace / SystemCap (требует компиляции c --enable-dtrace)
  • 36.
    Наш опыт: логированиев Firebird  Trace API + плагины  Системный аудит — управляется ядром, настраивается конфигом, пишется в лог на диске (по умолчанию) с ротацией (архивированием)  Пользовательская трассировка — управляется юзером (start-pause-resume-stop), конфиг задается в рантайме, лог пишется во временные файлы и удаляется по мере вычитывания клиентом
  • 37.
    Наш опыт: логированиев Firebird  Везде логируем ID объектов  Большинство событий спаренные — начало и конец  По завершении можем выдавать статистику — время выполнения и детализированные метрики  Есть функционал slow query log — через time_threshold  Дополнительная кастомизация — через include/exclude фильтры (regexp)
  • 38.
    Наш опыт: логированиев Firebird # трассируем медленные запросы database = myslowdb { log_statement_finish = true print_perf = true time_threshold = 10000 # 10 seconds } # трассируем изменения метаданных database = mycooldb { log_statement_start = true include_filter = %(CREATE|ALTER|DROP)% }
  • 39.
    В реальной жизнинадо сочетать  В логах — только алерты или подробно  От этого зависит частота снэпшот-мониторинга  Совсем интересно становится, если их можно связать вместе
  • 40.