Генератор вредоносной нагрузки для PostgreSQL
Поддерживаемые виды нагрузки
-
idle transactions— активные транзакции на горячих таблицах с интенсивной записью, которые ничего не делают на протяжении всего своего времени жизни. -
rollbacks— заведомо некорректные запросы, которые вызывают ошибки и увеличивают счётчик откатов. -
waiting transactions— один держатель блокировки циклически захватываетACCESS EXCLUSIVEна одну таблицу, пока менеджер с ограниченной частотой открывает N отдельных соединений (--wait-xacts.waiters), каждое из которых блокируется на ней — мерцающая «лесенка» заблокированных сессий, которая при неограниченном числе ожидающих (--wait-xacts.waiters=0) растёт, пока не исчерпаетсяmax_connectionsи новые клиенты не начнут получатьFATAL: sorry, too many clients already. -
deadlocks— одновременные транзакции, каждая из которых удерживает блокировки, нужные другим транзакциям. -
temporary files— запросы, сортирующие набор данных заведомо большеwork_mem, что приводит к сбросу временных файлов на диск при настройках сервера по умолчанию; увеличениеwork_mem(на уровне роли или базы данных) позволяет выполнить тот же запрос в памяти — сброс на диск исчезает (демонстрация устранения проблемы). -
terminate backends— завершение случайных серверных процессов (или запросов) с помощьюpg_terminate_backend()иpg_cancel_backend(). -
failed connections— исчерпание всех доступных соединений, после чего другие клиенты не могут подключиться к Postgres. -
fork connections— выполнение одного короткого запроса в отдельном соединении, что приводит к избыточному порождению дочерних процессов Postgres. -
backend-killer— одна сессия непрерывно утечёт подготовленные выражения (рост кэша планов), раздувая RSS серверного процесса вплоть до его завершения по OOM и перезапуска всего экземпляра; очень большое значение--backend-killer.plan-sizeделает каждый вызовPREPAREтяжёлым и медленным. -
slot-bloat— одиночный невостребованный физический слот репликации удерживает WAL, иpg_walрастёт без ограничений → диск заполняется → экземпляр уходит в PANIC; данные при этом не растут, контрольные точки продолжают выполняться, однако диск всё равно заполняется. -
wal-flood— множество параллельных воркеров, выполняющих цикличныеUPDATE(--jobs), заваливают WAL на первичном узле чистой скоростью записи, увеличивая лаг репликации и — когда переработка/архивирование не успевают — ростpg_walвплоть до переполнения диска; видимый с точки зрения активности аналогslot-bloat(переполнение диска здесь зависит от среды и не гарантировано). -
bloat-churn— множество параллельных воркеров с цикличнымиUPDATE(--jobs) по скорости обгоняют всё ещё работающий autovacuum, ломая HOT за счёт индексируемого поляupdated_at = now(), отчего раздуваются и куча, и индекс; нетронутый «хвост» таблицы не даётVACUUMобрезать файл. Это устраняемый аналогxmin-horizon-holderна основе атаки скоростью — симптом тот же, но после остановки noisia таблицу можно починить с помощьюVACUUM FULL,pg_repackилиREINDEX CONCURRENTLY. -
…дополнительные параметры времени выполнения смотрите во встроенной справке.
Отказ от ответственности
ВНИМАНИЕ: ИСПОЛЬЗУЙТЕ ТОЛЬКО В ЦЕЛЯХ ТЕСТИРОВАНИЯ. НЕ ЗАПУСКАЙТЕ NOISIA БЕЗ ПОЛНОГО ПОНИМАНИЯ ПОСЛЕДСТВИЙ — БЕЗРАССУДНОЕ ИСПОЛЬЗОВАНИЕ ПРИВЕДЁТ К ПРОБЛЕМАМ.
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ» БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ В ОТНОШЕНИИ ВАШИХ БАЗ ДАННЫХ. ИСПОЛЬЗУЕТЕ НА СВОЙ СТРАХ И РИСК.
Установка и использование
Смотрите страницу релизов.
Использование через Docker
docker pull lesovsky/noisia:latest
docker run --rm -ti lesovsky/noisia:latest noisia --help
Использование в собственном коде
Вы можете импортировать noisia и использовать нужные виды нагрузки в своём коде. Всегда применяйте контексты, чтобы избежать бесконечного выполнения. Пример ниже:
package main
import (
"context"
"fmt"
"github.com/lesovsky/noisia/waitxacts"
"github.com/rs/zerolog"
"log"
"os"
"time"
)
func main() {
config := waitxacts.Config{
Conninfo: "host=127.0.0.1",
Waiters: 10,
WaitersRate: 1,
ReportInterval: 1*time.Second,
LocktimeMin: 5*time.Second,
LocktimeMax: 20*time.Second,
}
logger := zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}).Level(zerolog.InfoLevel).With().Timestamp().Logger()
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)
defer cancel()
w, err := waitxacts.NewWorkload(config, logger)
if err != nil {
log.Panicln(err)
}
err = w.Run(ctx)
if err != nil {
fmt.Println(err)
}
}
Влияние нагрузки на окружение
Запущенные виды нагрузки могут негативно влиять на работу других приложений. Это может проявляться как деградация производительности, зависание транзакций, отмена запросов, разрыв соединений с клиентами и т. д.
| Вид нагрузки | Влияние? |
|---|---|
backendkiller |
Да: одна сессия раздувает RSS серверного процесса вплоть до завершения по OOM и полного перезапуска экземпляра; очень большое значение |
deadlocks |
Нет |
failconns |
Да: исчерпывает лимит |
forkconns |
Да: избыточное создание дочерних процессов Postgres; потенциально может привести к исчерпанию |
idlexacts |
Да: может приводить к раздуванию таблиц и индексов |
rollbacks |
Нет |
slotbloat |
Да: невостребованный слот репликации удерживает WAL; |
tempfiles |
Да: может увеличивать использование дискового пространства и снижать производительность хранилища |
terminate |
Да: уже установленные соединения с базой данных могут быть случайно разорваны |
waitxacts |
Да: блокирует таблицы с интенсивной записью, что приводит к блокировке параллельно выполняемых запросов |
walflood |
Да: интенсивная генерация WAL увеличивает лаг репликации и нагрузку на I/O; в ограниченной среде |
Демонстрация и руководства по настройке
Для каждого из эскалирующих видов нагрузки подготовлены отдельная демонстрация и руководство по настройке, охватывающие: как собрать надёжный стенд, отрегулировать давление, читать встроенный отчёт и восстановиться после.
-
docs/workloads/backend-killer.md— довести один серверный процесс до завершения по OOM и перезапустить экземпляр; ограничение памяти, отключение swap и увеличение нагрузки по планам. -
docs/workloads/slot-bloat.md— заполнитьpg_walодним забытым слотом репликации до полного диска; флаги командной строки, два рецепта стенда и восстановление после краша слота. -
docs/workloads/wal-flood.md— затопить WAL параллельными воркерами с цикличнымиUPDATE; честный контракт о зависимости от среды, условия переполнения диска, параметры демонстрации и отличия отslot-bloat. -
docs/workloads/bloat-churn.md— обогнать autovacuum по скорости, чтобы вырастить устраняемое раздувание кучи и индексов; троица, которая это строит, раскрытие способа починки после остановки (VACUUM FULL/pg_repack/REINDEX CONCURRENTLY), что смотреть через pgstattuple и чем атака скоростью отличается от атаки горизонтом вxmin-horizon-holder. -
docs/workloads/tempfiles.md— получить сброс временных файлов на диск при сортировке набора данных, превышающегоwork_mem, на сервере с настройками по умолчанию; как наблюдатьtemp_files/temp_bytesиlog_temp_files, и главный способ устранения — поднятьwork_mem, и сброс исчезнет. -
docs/workloads/waitxacts.md— выстроить очередь заблокированных сессий-ожидальщиков за одной удерживаемой блокировкой таблицы; демонстрация наблюдения (мерцающая «лесенка» сwait_event_type='Lock') и демонстрация каскада (неограниченные ожидальщики до исчерпанияmax_connections), а также трюк сsuperuser_reserved_connections, позволяющий держать мониторpostgresживым, пока клиентамappотказывают в подключении.
Участие в проекте
Лицензия
BSD-3. Подробности смотрите в файле LICENSE.