Безопасность и производительность
Какие гарантии даёт Winter Thread в отношении хранения payload и выполнения кода, и на какую модель стоимости вы соглашаетесь, когда каждая задача — это отдельный процесс ОС.
Модель безопасности
Хранилище payload доступно только владельцу
Оба транспорта без каналов ограничивают доступ к сериализованной задаче запустившим её пользователем:
TempFileTransport—chmod(0600)применяется сразу послеtempnam(), до того как будут записаны любые байты, и файл удаляется черезunlinkв течение микросекунд после возврата изproc_open. Окно, в течение которого он существует на диске, крошечное, но даже тогда прочитать его может только владелец.ShmTransport— сегмент создаётся черезshmop_open($key, 'n', 0600, $size), поэтому подключиться к нему может только пользователь-владелец.
Payload подписываются (по желанию)
Payload всегда (де)сериализуется через opis/closure — никогда не через нативный
unserialize() — поэтому сериализованное замыкание или анонимный класс безопасно переживает
границу процесса. Поскольку этот payload — исполняемый код, злоумышленник, способный его
подделать, мог бы выполнить произвольный код в дочернем процессе. Подпись закрывает эту брешь:
настройте секрет на движке — new AdaptiveEngine(secret: '…'),
(new ManualEngine())->withSecurity('…') или переменную окружения WINTER_THREAD_SECRET — и
родитель подписывает через HMAC каждый payload, а дочерний процесс (wRunner /
AdaptiveRunner) проверяет подпись перед десериализацией, отклоняя поддельные или
изменённые payload (защита от инъекции объектов). Подпись включается по желанию; всегда
включайте её, когда сериализуете замыкания или анонимные классы. Без секрета граница доверия
опирается на приватный, доступный только владельцу канал доставки. См.
Глубокое погружение в безопасность через метод движка security().
Формирование команды экранируется
Всё, что попадает в командную строку раннера — namespace, name, tag и каждое значение
--arg-* — пропускается через escapeshellarg. Ключ shm приводится к int, а проверка
зомби-процессов в macOS приводит PID к int перед вызовом ps. Не существует пути, по
которому аргумент задачи мог бы вырваться в шелл.
Аргументы видны
Пользовательские аргументы становятся флагами командной строки, поэтому они видны в ps и в
списках процессов. Никогда не передавайте секреты (токены, пароли) как аргументы start() —
получайте их внутри run() из вашего конфига или хранилища секретов.
Модель производительности
Процесс не бесплатен
Каждый вызов start() выполняет fork/exec нового процесса PHP: запуск интерпретатора,
автозагрузчик и собственный расход памяти. Эта изоляция и есть ценностное предложение, но она
означает, что схема подходит для крупнозернистой работы — задач, измеряемых десятками
миллисекунд и выше. Порождение процесса на каждую тривиальную операцию обойдётся дороже, чем
сэкономит; такие операции лучше объединять в пакеты.
Компромиссы доставки payload
| Транспорт | Стоимость | Примечания |
|---|---|---|
PipeTransport |
без доплаты | По умолчанию в CLI; небезопасен со Swoole |
TempFileTransport |
одна запись temp-файла + unlink |
Универсальный, минимальное касание диска |
ShmTransport |
только RAM | Без дискового I/O; нужен ext-shmop |
Стоимость сериализации растёт с размером payload, поэтому держите объекты задач лёгкими — id и
пути, а не большие наборы данных в памяти. Для крупных или высокочастотных payload
ShmTransport полностью обходит диск.
Гранулярность опроса join()
join() ожидает, опрашивая proc_get_status каждые 50 мс (usleep(50_000)). Это
разрешение и для детекции завершения, и для timeout, и оно не даёт ожидающему родителю крутить
процессор впустую. Это также означает, что join() может сообщить о завершении с задержкой до
~50 мс после фактического выхода дочернего процесса — пренебрежимо мало для реальных задач,
но стоит знать при микробенчмарках.
Управление конкурентностью — на вас
Ничто не ограничивает количество порождаемых процессов. Для больших пакетов ограничивайте конкурентность пулом, чтобы не исчерпать CPU или память — см. Параллельные задачи.
Связанное
- Swoole и доставка payload
- Параллельные задачи — ограничение конкурентности
- Установка и требования —
ext-shmop,opis/closure