Pro Features

Общие переменные — Redis

Общее состояние между машинами агентов — Redis-драйвер шагов shared variables в распределённых мульти-инстанс прогонах

Обзор

Общие переменные координируют VU внутри прогона — очереди producer/consumer, общие счётчики, барьеры. Встроенный драйвер memory делит их между VU одного процесса агента. Драйвер redis на этой странице — платная возможность (тарифы Scale и Enterprise), которую зарегистрированные платные агенты добавляют на тот же seam драйверов: хранилище переезжает в Redis-сервер, и все агенты, указывающие на него, делят одно состояние — очередь, наполняемая на одной машине, разбирается на другой.

На OSS-сборке, или на агенте без настроенного URL, driver: redis падает с перечнем зарегистрированных драйверов — всегда видно, какая сборка нужна.

Всё остальное идентично драйверу memory — форма шага, операции (set / get / increment / append / pop), блокирующий wait_for, маппинги extract и обязательные объявления shared_variables: с валидацией до старта. Меняется только хранилище:

ДрайверХранилищеОбщее между
memory (по умолчанию)Карта внутри процессаVU одного процесса агента
redisRedis-серверVU всех агентов, указывающих на сервер

Настройка агента

URL Redis — настройка уровня агента: общая переменная — это инфраструктура, а не эндпоинт конкретного шага, поэтому url в шаге нет. Каждый агент, который должен присоединиться к общему хранилищу, запускается с:

# .env на машине агента
PERFSCALE_SHARED_REDIS_URL=redis://:secret@redis.internal:6379/0
  • redis://[:password@]host:6379[/db], или rediss:// для TLS.
  • Агенты без этой переменной просто не регистрируют драйвер — их шаги с driver: redis падают с перечнем зарегистрированных драйверов.
  • Два независимых окружения на одном Redis-сервере: используйте разные логические БД в URL (/0, /1, …) — имя переменной ничего не значит между БД.
  • Агенты на другой машине: не публикуйте «голый» Redis на публичном порту. В infra compose есть redis-gateway — nginx stream с TLS-терминацией на :6479; внешние агенты используют rediss://:<password>@<host>:6479/0.

Соединение мультиплексированное и само восстанавливается; сбой брокера рушит затронутый шаг, а не агента.

Пример

Объявления живут в конфиг-файле, точно так же, как с memory:

# config.yaml
shared_variables:
  pending_orders: []      # список → append / pop
  approved_count: 0       # число → increment
# producer.yaml — запускается на агенте A
steps:
  - name: enqueue order
    use: std/set_shared_variable@v1
    with:
      driver: redis
      name: pending_orders
      op: append
      value: { id: "${{ uuid }}", total: 42.50 }
# consumer.yaml — запускается на агенте B, разбирает то, что произвёл A
steps:
  - name: take next order
    use: std/get_shared_variable@v1
    with:
      driver: redis
      name: pending_orders
      op: pop
      wait_for: { length_gte: 1, timeout_ms: 10000 }
    outputs:
      order_id: value.id

Атомарность — одна Redis-команда на операцию

Каждая операция маппится на одну атомарную серверную команду — тот же контракт, что драйвер memory даёт одним захватом блокировки. Нет пары «прочитал-изменил-записал», которой можно было бы срасовать, и нет примитива блокировки, на котором можно было бы зависнуть.

ОперацияRedis-командаРезультат
increment (целая дельта)INCRBYновое значение, остаётся целым
increment (дробная дельта)INCRBYFLOATновое значение
appendRPUSHновая длина списка
popLPOPпервый элемент, null для пустого
setSET / DEL+RPUSH (списки)записанное значение
getGET / LRANGE (списки)записанное значение

Значения хранятся так, чтобы эти команды применялись напрямую: числа — простыми строками, элементы списков — JSON, остальные скаляры — JSON-строками. get различает список и скаляр через серверный TYPE ключа, поэтому агенты всегда корректно читают записи друг друга.

Жизненный цикл прогона

  • Ключи живут по адресу perfscale:shared:<name>.
  • Старт прогона: каждый агент пересиживает объявленные ключи (DEL + начальное значение) и удаляет ключи, оставшиеся от его прошлого прогона. Прогон всегда стартует с объявленных начальных значений — перенос состояния между прогонами намеренно невозможен.
  • Старт нескольких агентов: каждый агент пересиживает в момент своего старта, поэтому значение, записанное до подключения последнего агента, будет сброшено. Паттерны, строящие состояние во время прогона (блок before:, наполняющий очередь, одновременно стартующие producer'ы), не затронуты; не рассчитывайте на «прогретое» хранилище, пока все агенты не подключились.
  • wait_for опрашивает сервер с небольшой паузой между проверками — на удалённом Redis каждый опрос это сетевой round-trip, поэтому выбирайте таймауты в секундах, а не в миллисекундах.