Модель процессов и жизненный цикл
Localzet Server использует многопроцессную архитектуру Master-Worker для обеспечения высокой производительности и отказоустойчивости.
Жизненный цикл Master Process
Фаза 1: Инициализация (Initialization)
Мастер-процесс начинает работу с последовательной инициализации всех компонентов системы:
Server::runAll()
├── checkSapiEnv() // Проверка окружения
├── initStdOut() // Инициализация потоков вывода
├── init() // Настройка событий и обработчиков
├── parseCommand() // Разбор командной строки
├── checkPortAvailable() // Проверка доступности портов
├── lock() // Файловая блокировка
├── daemonize() // Переход в режим демона (опционально)
├── initServers() // Инициализация серверов
├── installSignal() // Установка обработчиков сигналов
├── saveMasterPid() // Сохранение PID мастера
└── displayUI() // Отображение интерфейса
Детали инициализации
Проверка окружения (checkSapiEnv)
Мастер-процесс проверяет:
- Запуск из CLI или Micro SAPI
- Наличие необходимых расширений PHP (
pcntl,posixдля Unix) - Доступность критических функций PHP (не должны быть в
disable_functions)
Демонизация (daemonize)
Процесс демонизации включает двойной fork для полного отключения от терминала:
1. Первый fork():
- Родительский процесс завершается (exit 0)
- Дочерний процесс продолжает работу
2. posix_setsid():
- Создание новой сессии
- Отключение от управляющего терминала
3. Второй fork():
- Предотвращает восстановление связи с терминалом
- Финальный процесс становится демоном
Установка сигналов (installSignal)
Мастер-процесс регистрирует обработчики для следующих сигналов:
| Сигнал | Действие | Описание |
|---|---|---|
SIGINT | Остановка | Немедленная остановка всех процессов |
SIGTERM | Остановка | Остановка с ожиданием завершения |
SIGQUIT | Graceful Stop | Плавная остановка с закрытием соединений |
SIGUSR1 | Reload | Горячая перезагрузка кода |
SIGUSR2 | Graceful Reload | Плавная перезагрузка |
SIGHUP | Перезапуск | Полный перезапуск сервера |
SIGIOT | Статистика | Запрос статистики от worker процессов |
SIGIO | Соединения | Запрос информации о соединениях |
Фаза 2: Создание Worker Processes
После инициализации мастер создает дочерние процессы:
forkServers()
├── Для каждого сервера:
│ ├── Определение количества worker процессов ($server->count)
│ └── while (count < required):
│ └── forkOneServerForLinux()
│ ├── pcntl_fork()
│ ├── В родителе: сохранение PID
│ └── В дочернем: инициализация worker
Механизм форкинга:
// Родительский процесс (Master)
if ($pid > 0) {
// Сохраняем PID нового worker
static::$pidMap[$serverId][$pid] = $pid;
static::$idMap[$serverId][$id] = $pid;
// Продолжаем создавать другие процессы
}
// Дочерний процесс (Worker)
elseif ($pid === 0) {
// 1. Очистка состояния
static::$pidsToRestart = static::$pidMap = [];
// 2. Закрытие других серверов (worker обслуживает только один сервер)
foreach (static::$servers as $key => $oneServer) {
if ($oneServer->serverId !== $server->serverId) {
$oneServer->unlisten();
unset(static::$servers[$key]);
}
}
// 3. Инициализация Event Loop
static::$globalEvent = new EventLoopClass();
// 4. Настройка пользователя процесса
$server->setUserAndGroup();
// 5. Запуск сервера
$server->run();
// 6. Запуск Event Loop (блокирующий вызов)
static::$globalEvent->run();
}
Фаза 3: Мониторинг (Monitoring)
Мастер-процесс переходит в режим мониторинга:
monitorServers()
├── Бесконечный цикл:
│ ├── Проверка статуса worker процессов
│ ├── Обработка сигналов
│ ├── Перезапуск упавших процессов
│ └── Graceful reload (если запрошен)
Мониторинг процессов:
while (true) {
// Для каждого worker процесса
foreach (static::$pidMap as $serverId => $pids) {
foreach ($pids as $pid) {
// Проверка существования процесса
if (!posix_kill($pid, 0)) {
// Процесс завершен - пересоздаем
static::forkOneServerForLinux($server);
}
}
}
// Обработка сигналов (через signal handler)
pcntl_signal_dispatch();
// Пауза перед следующей проверкой
usleep(10000); // 10ms
}
Жизненный цикл Worker Process
Инициализация Worker
После форкинга worker процесс проходит следующую инициализацию:
- Очистка состояния: Удаление ссылок на другие серверы и процессы
- Создание Event Loop: Инициализация событийного цикла для данного процесса
- Установка обработчиков: Регистрация callback-функций для событий
- Привязка к сокету: Начало прослушивания входящих соединений
- Запуск Event Loop: Переход в асинхронный режим работы
Работа с соединениями
Принятие соединения:
1. Event Loop обнаруживает событие "readable" на listening socket
2. Вызывается Server::acceptTcpConnection()
3. Создается объект TcpConnection
4. Регистрируется callback для чтения данных
5. Вызывается onConnect callback (если установлен)
Обработка данных:
1. Event Loop обнаруживает данные на клиентском сокете
2. TcpConnection::baseRead() читает данные в recvBuffer
3. Протокол прикладного уровня проверяет целостность пакета (input)
4. Когда пакет полный, вызывается decode()
5. Декодированные данные передаются в onMessage callback
6. Бизнес-логика обрабатывает запрос
7. Ответ кодируется протоколом (encode)
8. Данные отправляются клиенту через send()
Управление памятью Worker
Буферизация:
- recvBuffer: Буфер приема необработанных данных
- sendBuffer: Буфер отправки, ожидающий записи
- currentPackageLength: Текущая длина ожидаемого пакета
Кеширование:
// Кеш запросов (для оптимизации парсинга)
static $requests = [];
// Кеш применяется для:
// 1. Повторяющихся HTTP запросов
// 2. Избежания повторного парсинга идентичных данных
// 3. Оптимизации использования памяти
Состояния процессов
Состояния Master Process
| Состояние | Значение | Описание |
|---|---|---|
STATUS_INITIAL (0) | Инициализация | Начальное состояние перед запуском |
STATUS_STARTING (1) | Запуск | Создание worker процессов |
STATUS_RUNNING (2) | Работа | Нормальная работа, мониторинг workers |
STATUS_SHUTDOWN (4) | Остановка | Процесс остановки |
STATUS_RELOADING (8) | Перезагрузка | Плавная перезагрузка |
Состояния Worker Process
Worker процесс имеет аналогичные состояния, но работает независимо от мастера после запуска.
Состояния соединения (TcpConnection)
| Состояние | Значение | Описание |
|---|---|---|
STATUS_INITIAL (0) | Инициализация | Создание объекта |
STATUS_CONNECTING (1) | Подключение | Установка соединения |
STATUS_ESTABLISHED (2) | Установлено | Активное соединение |
STATUS_CLOSING (4) | Закрытие | Процесс закрытия |
STATUS_CLOSED (8) | Закрыто | Соединение закрыто |
Управление жизненным циклом
Остановка сервера
Немедленная остановка (SIGINT / SIGTERM):
1. Мастер получает сигнал
2. Отправка SIGTERM всем worker процессам
3. Ожидание завершения (timeout = stopTimeout)
4. Принудительное завершение (SIGKILL) если timeout
5. Очистка ресурсов и выход
Плавная остановка (SIGQUIT):
1. Мастер получает SIGQUIT
2. Установка флага gracefulStop = true
3. Отправка SIGQUIT всем worker процессам
4. Worker процессы:
- Прекращают принимать новые соединения
- Закрывают пустые соединения
- Ожидают завершения обработки активных запросов
- Закрывают соединения после обработки
5. По завершении всех соединений - выход
Перезагрузка кода
Горячая перезагрузка (SIGUSR1):
1. Мастер получает SIGUSR1
2. Отправка SIGUSR1 всем worker процессам
3. Worker процесс:
- Завершает текущую обработку
- Перезагружает PHP файлы (autoload)
- Сохраняет активные соединения
- Продолжает работу с новым кодом
Плавная перезагрузка (SIGUSR2):
1. Мастер получает SIGUSR2
2. Для каждого worker процесса последовательно:
a. Создание нового worker с новым кодом
b. Ожидание завершения старого worker
c. Переход к следующему worker
3. Все соединения плавно переносятся на новые процессы
Межпроцессное взаимодействие
Обмен данными через файлы
Статистика:
- Путь:
$statusFile - Формат: Сериализованные данные
- Обновление: По сигналу
SIGIOT
Соединения:
- Путь:
$connectionsFile - Формат: Сериализованные данные о соединениях
- Обновление: По сигналу
SIGIO
PID-файлы
$pidFile: PID мастера- Используется для проверки запущенности сервера
- Блокировка предотвращает множественный запуск
Изоляция и безопасность
Изоляция памяти
Каждый worker процесс имеет полностью изолированную память:
- Отдельное адресное пространство
- Независимые глобальные переменные
- Изолированные статические данные
- Независимые подключения к БД
Управление привилегиями
Worker процессы могут работать от непривилегированного пользователя:
$server->user = 'www-data';
$server->group = 'www-data';
// После привязки к порту:
posix_setgid($gid);
posix_initgroups($user, $gid);
posix_setuid($uid);
Это обеспечивает:
- Минимальные привилегии (principle of least privilege)
- Безопасность при компрометации процесса
- Соответствие требованиям безопасности

