Историческое предисловие
Как известно, основная задача DBA - обеспечить наиболее эффективную и производительную работу вверенной ему в сопровождение СУБД. Для выполнения задачи одно из основных требований - умение определить насколько производительно/эффективно СУБД справляется с получаемой нагрузкой и выдает требуемый результат. Для этого необходимо определить такое понятие как производительность СУБД. Потому, что очень важно, для начала, хотя бы обеспечить мониторинг и иметь возможность сразу сказать - в каком состоянии СУБД - минимальная загрузка, оптимальная, перегруз, авария. Однако, как выясняется, общего понятия "производительность СУБД" до недавнего времени не существовало. Каждый DBA понимал под производительностью, то , что лично ему нравится - количество запросов в секунду, количество зафиксированных транзакций, среднее время отклика СУБД и даже процент утилизации CPU+RAM или вывести на экран десяток другой графиков мониторинга и каким то мистическим образом определить хорошо работает СУБД или плохо.
Ситуацию надо было менять , ибо , как говорится - для того, что бы чем то управлять и улучшать надо это уметь измерять.
Для начала надо определиться с определением и ответить на главный вопрос - что есть производительность СУБД ?
Вспоминая физику , можно использовать базовое понятие:
В физике производительность — это величина, которая обозначает объём работы, выполняемый за единицу времени (например, за час или за день). По-другому её можно назвать скоростью выполнения работы
Данное определение, было взято за основу. Осталось уточнить - что такое объем работы выполняемой СУБД ?
Методы расчета метрики производительности
Самый первый вариант расчета метрики
На этапе нагрузочного тестирования одного проекта, возникла необходимость - оценить степень влияния изменений вносимых разработчиками, на эффективность работы СУБД. Тогда впервые и возникла идея - надо считать метрику производительности .
А может быть производительность СУБД это вектор: (N1, N2, N3), где:
N1 - количество активных сессий
N2 - количество транзакций
N3 - количество запросов к СУБД в секунду.
https://habr.com/ru/posts/787966/
В принципе, метрика вполне себе работала и показывала ожидаемые результаты - основная часть изменений не оказывали вообще никакого влияния на работоспособность СУБД . В результате было сохранено очень много рабочего времени , потому , что не нужно стало объяснять и доказывать неэффективности предлагаемых изменений. Все видно на графиках и в таблицах.
Однако, как можно понять - метрика в общем то не совсем производительность считает. Очень важный момент - "количество активных сессий" , и тут возможна первая аномалия.
Аномалия учета ожиданий
Возможна ситуация - особенно при продуктивной нагрузке - работоспособность СУБД падает, а метрика растет.
Причина- количество активных сессий учитывает не только сессии выполняющие запросы , но и находящиеся в состоянии ожидания.
Порядок расчёта метрики производительности СУБД был изменен.
Второй вариант расчета метрики
Было принято решение изменить методику расчета, используя вектор:(N1, N2, N3, N4, N5), где:
N1 - количество страниц shared_buffer , прочитанных в секунду
N2 - количество страниц shared_buffer, записанных в секунду
N3 - количество страниц shared_buffer, измененных в секунду
N4 - количество завершенных запросов в секунду
N5 - количество зафиксированных транзакций в секунду
https://habr.com/ru/posts/804899/
Этот вариант проработал дольше . И обеспечил хорошую базу для работ по статистическому анализу производительности СУБД.
Корреляционный анализ для решения инцидентов производительности СУБД / Хабр (habr.com)
Нагрузочное тестирование СУБД в облачной среде — часть 1 / Хабр (habr.com)
Нагрузочное тестирование СУБД в облачной среде — часть 2. Итоги и результат / Хабр (habr.com)
Статистический анализ результатов benchmark PostgreSQL / Хабр (habr.com)
Однако, благодаря обратной связи в комментариях к статьям(чуть позже найду этот комментарий, добавлю), была обнаружена еще одна аномалия .
Аномалия изменения плана выполнения запроса.
Для того, что бы обнаружить аномалию достаточно было провести очень простой эксперимент:
Создаем большие таблицы: родитель-потомок.
В таблицах не создаем индексы.
Подготавливаем запрос. Поскольку индексов нет , используется последовательное чтение.
Выполняем несколько итераций, фиксируем время выполнения запроса и показатель производительности СУБД.
Создаем индексы для таблиц.
Выполняем итерации того же самого запроса.
Фиксируем время выполнения запроса и показатель производительности СУБД.
Аномалия заключается в том, что запрос стал работать на порядки быстрее , стоимость запроса кардинально снизилась , следовательно эффективность резко возросла, но значение метрики - уменьшается.
Причина: При выполнении индексного доступа к данным количество обработанных страниц shared_buffer существенно уменьшается. А при использовании метода доступа Index Only Scan вообще будет нулевым. В результате значение метрики производительности уменьшается.
Третий вариант расчета метрики
Для решения проблемы аномалии изменения плана выполнения запроса, расчет метрики был изменен. Необходимо было ввести новые определения .
Операционная(результативная) скорость
Полезными операциями(результатами) работы СУБД являются:
Количество строк выданных пользователю.
Количество запросов выполненных пользователем.
Количество зафиксированных пользователем транзакций.
Разделив количество на количество секунд (DB Time), которые потребовались на выполнения операций СУБД в изменяемый промежуток получаем - вектор , определяющий операционную(результативную) скорость:
QPS: Количество запросов в секунду.
TPS: Количество транзакций в секунду.
RPS: Количество строк в секунду.
Для того, что бы иметь одну цифру используется модуль вектора ( QPS , TPS , RPS ).
Полученное значение и будет считаться операционной скоростью.
Объемная скорость
Работа СУБД заключается в обработке блоков информации:
Прочитанные разделяемые блоки
"Загрязнённые" разделяемые блоки
Записанные разделяемые блоки
Прочитанные локальные блоки
"Загрязнённые" локальные блоки
Записанные локальные блоки
Прочитанные временные блоки
Записанные временные блоки
Подробнее о разделяемых блоках: WAL в PostgreSQL: 1. Буферный кеш / Хабр (habr.com)
О локальных и временных блоках , пока не нашел. Найду , добавлю.
Таким образом, применив тот же подход , что и для расчета операционной скорости получим- вектор, определяющий объёмную скорость :
RSBS : Прочитанные разделяемые блоки в секунду.
DSBS : "Загрязнённые" разделяемые блоки в секунду.
WSBS : Записанные разделяемые блоки в секунду.
RLBS : Прочитанные локальные блоки в секунду.
DLBS : "Загрязнённые" локальные блоки в секунду.
WLBS : Записанные локальные блоки в секунду.
RTBS : Прочитанные временные блоки в секунду.
WSBS: Записанные временные блоки в секунду.
Аналогично, для получения значения используем модуль вектора ( RSBS , DSBS , WSBS , RLBS , DLBS , WLBS , RTBS , WSBS ).
Полученное значение и будет объемной скоростью.
Расчет метрики "производительность СУБД"
Отношение операционной скорости к объемной скорости и будет принято как производительность СУБД.
Как видно, производительность СУБД в течение заданного промежутка времени прямо пропорционально объёму полученного результата и обратно пропорциональна объёму обработанной для получения результата информации.
Другими словами - данная метрика показывает - насколько эффективно СУБД выдаёт результат, обрабатывая объем информации .
Т.е. если план запроса изменился так, что запрос стал выполняться быстрее и читать меньше блоков (стоимость запроса снизилась) , то в этом случае значение метрики - увеличится .
Для удобства , обозначим производительность СУБД как CPI. Тогда производительность СУБД в момент времени t , есть значение дискретной функции CPI(t).
Для сглаживания графика и исключения выбросов используется медианное сглаживание: Вопрос о скользящей средней и медиане / Хабр (habr.com)
Временной/исторический анализ производительности
Задача анализа производительности СУБД сводится к анализу временного ряда, сформированного из значений функции CPI(t) , для значений t от начала до окончания анализируемого периода .
Например: Корреляционный анализ для определения причин деградации производительности СУБД / Хабр (habr.com)
Параметрическая оптимизация производительности
Задача по оптимизации производительности СУБД сводится к задаче оптимизации функции CPI(t) при изменении набора конфигурационных параметров СУБД .
Задача - определить комбинацию параметров дающих наибольший прирост производительности .
На текущий момент, первое, что сразу приходит в голову - использовать метод покоординатного спуска (в данном случае - подъёма )
https://habr.com/ru/posts/848496/
Для анализа результатов каждой итерации применяется Статистический анализ результатов benchmark PostgreSQL / Хабр (habr.com) .
Примечание
В настоящее время в стадии сбора данных несколько экспериментов по параметрической оптимизации. Результаты будут опубликованы после окончания и анализа.
В комментариях к предыдущей статье было предложено использовать не Евклидову, а Манхеттенскую метрику для расчета модуля векторов операционной и объёмной скорости . Поскольку , в общем случае, размерности векторов нельзя считать независимыми . В настоящий момент , тема в проработке. Возможно смена метрики позволит избежать каких то еще аномалий , которые пока не проявились.
Комментарии (6)
vvm13xx
11.10.2024 18:21Самое главное - кого эта база обслуживает и зачем. В зависимости от бизнес-требований где-то важны одни вещи, где-то другие. Возможна неоднородная ситуация, где каким-то пользователям необходимо обеспечить быстрый отклик, а какие-то пользователи могут быть не особо важны, и оптимизация для них может быть попросту вредной. Так что начинать надо с анализа бизнес-требований, так что метрики, описанные вами, мягко говоря, не особо полезны. Вы можете что-нибудь наоптимизировать по ним и получить якобы результат, но в итоге бизнес может не получить того, что реально нужно.
Короче, почитайте книжки за авторством Cary Millsap про Method-R. Они уже древние, но всё ещё очень полезные.vvm13xx
11.10.2024 18:21Пример: есть юзеры категории 1 (приоритетные) и юзеры категории 2 (не приоритетные). 1-й категории вреден индекс I на таблице T, 2-й категории полезен индекс I на таблице T. Но, предположим, вы оперируете только общей картиной и индекс создали, поскольку с ним общие метрики улучшились. Но самое-то важное не общие метрики, а то, что приоритетные юзеры пострадали.
rinace Автор
11.10.2024 18:21каким-то пользователям необходимо обеспечить быстрый отклик, а какие-то пользователи могут быть не особо важны, и оптимизация для них может быть попросту вредной.
А можно пример из жизни такой оригинальной архитектуры и бизнес требований?
gleb_l
Если бы из баз только читали, то подход был бы годным. Чем выше отношение W / (R+W) - тем больше погрешность метода. При достаточно высоком отношении влияние затрат на ожидание/постановку/снятие эксклюзивных блокировок будет порядково выше, чем затрат на операции поиска/выборки. Аналог - модель идеального газа в термодинамике и нелинейного после определенных концентраций молекул - когда влияние их друг на друга начинают существенно искажать простую теорию. Другой аналог - зависимые или независимые случайные величины. Начиная с какой-то величины созависимости пренебрежение ей делает независимую модель практически неработоспособной.
Соответственно, если проверять производительность в близких к реальным условиях - нужно работать на близких к реальным нагрузочных смесях.
Кроме этого - scan и seek в условиях параллельной активности по записи отличаются не только по O(N) vs O(logN) - scan в условиях параллельных записей практически убивает параллелизм, а seek за счет точечных блокировок позволяет системе жить при гораздо более высоких отношениях W / (R+W).
Отсюда вывод - производительность СУБД зависит не только от настройки (задача ДБА), но и от способа работы с ней (задача Дата Архитектора). Даже при наличии индексов или шард один неоптимально написанный запрос убьет перформанс сотни остальных, написанных правильно. И значит, мы можем говорить о производительности СУБД только в контексте ее связки с приложением, которое с ней работает - то есть о производительности всей [b]информационной системы[/b]
И далее - вывод, который непосредственно идет из последнего абзаца - только Дата Инженер / Дата Архитектор компетентны в оптимальной работе с БД. Значит, если построить слой, который позволит менее компетентным разработчикам работать с данными только определенными вышеуказанными фигурами способами - это будет гарантировать производительность системы. Самые надежные способы, которые нельзя обойти by design - это внутрибазное программирование - то есть SP и TVF в первую очередь. Этот способ заодно абсолютно надежно решает и проблемы разделения доступа к БД со стороны разных систем - размещением этих объектов в разных схемах. Оба этих свойства дают абсолютную гарантию того, что автомобили фуллстеков поедут строго по заранее определенным и проверенным дорогам, а не будут двигаться по территории построенного архитектором города хаотически, сталкиваясь и снося все вокруг. Ценность этой гарантии порядково выше (для тех, кто понимает эту ценность) гипотетической возможности заменить бакенд на «аналогичный», которую усиленно педалируют адепты CRUD- и code-first подходов.
rinace Автор
А можете предоставить любые расчёты или результаты экспериментов, для обоснования следующих утверждений:
Ну и мой любимый вопрос - производительность вы как считаете ?
Что значить "зависит"?
Следующее утверждение на чем основано
Это ваш личный вывод ?
gleb_l
Да, к сожалению, документами подтвердить не могу. Только личный опыт (. Если нужно на гербовой - можно просто игнорировать ).