Готовый перевод Mastering Swoole PHP: Build High Performance Concurrent System with Async and Coroutines / Осваиваем Swoole PHP: построение высокопроизводительной конкурентной системы с асинхронностью и корутинами: Проблемы конкурентности

Внимание! Этот перевод, возможно, ещё не готов, так как модераторы установили для него статус «идёт перевод»

Проблемы конкурентности.

У вас может возникнуть резонный вопрос: откуда же берутся проблемы конкурентности?

Один из главных недостатков PHP-FPM в том, что он связывает отдельное соединение с довольно тяжелым процессом, и неспособен динамически масштабироваться для обработки большего количества одновременных запросов.

Представьте 100 запросов, пришедших одновременно, и 100 процессов, которые требуются для их обслуживания.

Кроме того, представьте и 100 подключений к базе данных, поскольку открытое соединение с БД нельзя использовать повторно для других запросов.

В теории, если мы будем рассматривать скрипт, который всего лишь возвращает "Hello world", процесс PHP будет выполнен за предсказуемый и короткий промежуток времени. Больших проблем не предвидится, задействованы только процессорные вычисления, и результат будет получен очень быстро.

Но в реальности, современные веб-приложения всегда включают в себя и внешние операции ввода-вывода: они обращаются к базе данных, вызывают HTTP сервисы (к примеру, OAuth), выполняют массу дорогостоящих действий, вроде отправки почты, и так далее. Время ожидания результата внешних операций зачастую не поддаётся оценке, а по множеству причин результат может не вернуться вообще. И вот у нас куча процессов, ожидающих I/O, но не выполняющих на сервере ничего полезного.

Общая идея при решении проблемы конкурентности - сделать процессы асинхронными. Мы рассмотрим несколько различных способов осуществления такой возможности.

До того, как Swoole PHP и другие CLI фрейморки завоевали популярность, распространённым решением проблемы для отделения пользователя от внешних вызовов АПИ и запросов было использование очереди. Вам наверняка знакомы такие решения, как Redis, или очереди в базе данных из Laravel. На уровне приложения вы всего лишь помещали данные для задачи в очередь, а позже вызывали другой, фоновый процесс, который обрабатывал задачу асинхронно.

Вот минус такого подхода: как только вы помещали данные для задачи в очередь, в текущем запросе у вас больше не было возможности контролировать ход исполнения. Вам приходилось снова опрашивать HTTP сервер, чтобы узнать, закончено ли выполнение фоновой задачи, или ещё нет.

Синхронный процесс:

Рисунок 4.1 (HTTP запрос в синхронном режиме)

Это обычный случай для PHP-FPM приложений - весь процесс соединения может быть заблокирован на каждом из уровней. Все компоненты могут быть заняты, ожидая результатов от медленного внешнего поставщика данных. И общая задержка ответа на запрос с каждым медленным уровнем будет расти тоже.

Асинхронный процесс:

Систему, описанную чуть выше, можно улучшить, сделав запрос асинхронным. Прежде всего изменим АПИ так, чтобы он помещал задачу в очередь и возвращал подтверждение клиенту. Затем отдельными запросами будем периодически опрашивать базу данных, пока там не появится результат выполнения нашей задачи*. Процесс обработки запроса становится «черным ящиком», и больше не замедляет ту часть АПИ, которая обращена к клиенту.

--------------------
* От переводчика: при таком подходе, как правило, задачи из очереди запускаются на выполнение с помощью планировщика (например, cron).

Вот общее представление о том, как работают асинхронные процессы. Этот подход может быть использован при запросах с клиентской стороны (из браузера), и даже представлен в виде системных вызовов к ядру Linux для операций ввода-вывода.

Клиентская сторона, вместо того, чтобы удерживать PHP процесс и ожидать ответа на текущий запрос, получает быстрое подтверждение о том, что задача поставлена в очередь, и проверяет результат выполнения другими запросами.

Но проблема остаётся проблемой, ведь мы по-прежнему тратим ресурсы на дополнительные HTTP запросы, проверяя статус выполнения.

Есть ли лучшее решение, чем терять ресурсы на таких запросах?

Для библиотек с поддержкой мутиплексирования I/O, вроде Swoole PHP, становится возможным использование одного процесса несколькими клиентами сразу, и ожидание результата перестаёт быть большой проблемой. Для каждого клиента можно даже организовать отдельный постоянный канал через WebSocket без больших затрат памяти и без умножения процессов Linux.

В этом великая сила решения - клиентские I/O больше не привязаны к процессам Linux.

Вы можете заметить, что некоторые безсерверные сервисы, вроде AWS Lambda, до сих пор не отделяют клиентский I/O от процессов Linux. Решение не самое лучшее, и мы надеемся, что со временем они пересмотрят свой подход.

Внимание! Этот перевод, возможно, ещё не готов.
Его статус: идёт перевод

Переведено на Нотабеноиде
http://notabenoid.org/book/81342/496684

Переводчики: Kee

Настройки

Готово:

100.00% КП = 1.0