Noisia: генератор вредоносной нагрузки для PostgreSQL

Генератор вредоносной нагрузки для 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 и полного перезапуска экземпляра; очень большое значение plan-size делает каждый вызов PREPARE тяжёлым и медленным

deadlocks

Нет

failconns

Да: исчерпывает лимит max_connections; другие клиенты не могут подключиться к Postgres

forkconns

Да: избыточное создание дочерних процессов Postgres; потенциально может привести к исчерпанию max_connections

idlexacts

Да: может приводить к раздуванию таблиц и индексов

rollbacks

Нет

slotbloat

Да: невостребованный слот репликации удерживает WAL; pg_wal растёт до заполнения файловой системы, после чего экземпляр больше не может писать и уходит в PANIC

tempfiles

Да: может увеличивать использование дискового пространства и снижать производительность хранилища

terminate

Да: уже установленные соединения с базой данных могут быть случайно разорваны

waitxacts

Да: блокирует таблицы с интенсивной записью, что приводит к блокировке параллельно выполняемых запросов

walflood

Да: интенсивная генерация WAL увеличивает лаг репликации и нагрузку на I/O; в ограниченной среде pg_wal растёт до переполнения диска и экземпляр уходит в PANIC

Демонстрация и руководства по настройке

Для каждого из эскалирующих видов нагрузки подготовлены отдельная демонстрация и руководство по настройке, охватывающие: как собрать надёжный стенд, отрегулировать давление, читать встроенный отчёт и восстановиться после.

  • 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 отказывают в подключении.

Участие в проекте

  • Pull request-ы приветствуются.

  • Идеи можно предлагать здесь.

  • О грамматических ошибках или опечатках сообщайте здесь.

Лицензия

BSD-3. Подробности смотрите в файле LICENSE.

© 2026 meganuke