Как запустить 5000 потоков параллельно с GET запросами?

Стоит задача держать постоянно 5000 потоков, которые будут делать GET запросы к API (15-20 секунд на запрос) (на данный момент 1000, но в ближайшее время масштабирование до 5000 точно)

Мой основной язык PHP.
Сейчас система работает через очереди, 300 воркеров с однопоточным CURL. На одной машине (AMD Ryzen 7 1700X 8 ядер, 64гб RAM). Стек Yii2-queue + mysql driver + supervisor. В целом все работает.
Но сделать на таком стеке 5000, и даже 1000 воркеров кажется неправильным (даже просто запустить 1000 воркеров проблематично было)

Собственно вопросов несколько
1. Как будет правильнее сделать это средствами PHP?
  • Я планировал переезд на RabbitMQ, (мне не нужно хранить сообщения после получения воркерами, мне важно знать что сообщения доставлены, поэтому выбрал RabbitMQ вместо Apache Kafka, но ни с одной системой плотно не работал)
  • Распараллелить выполнение в самом воркере с помощью ReactPHP или лучше GuzzleAsync. В таком случае не придется держать 5000 воркеров именно
  • При необходимости добавить еще машин. При этом обращаться к одной базе или делать репликацию, я еще не знаю

2. "Правильно ли" это вообще делать с помощью PHP или это все таки задача уже других языков которые умеют в параллельное выполнение, корутины? Go, NodeJs?
3. Может уже есть готовые решения в виде библиотек на PHP? Искал, но не нашел
  • Вопрос задан
  • 1031 просмотр
Решения вопроса 2
Vamp
@Vamp
Распараллелить выполнение в самом воркере с помощью ReactPHP или лучше GuzzleAsync. В таком случае не придется держать 5000 воркеров именно

Вариант с GuzzleAsync - самый лучший. Под капотом он использует возможности curl_multi_exec, которые позволяют асинхронно отправлять несколько запросов, не плодя при этом лишние процессы. Не уверен конечно, что осилит 5000 параллельных запросов, но даже если и не сможет, то можно разделить 5000 между несколькими воркерами.

2. "Правильно ли" это вообще делать с помощью PHP или это все таки задача уже других языков которые умеют в параллельное выполнение, корутины? Go, NodeJs?

У вас нагрузка в основном IO bound, так что не имет значения какой язык выбрать. Главное чтобы он поддерживал IO multiplexing (который поддерживается в PHP через вышеупомянутый curl_multi_exec).

3. Может уже есть готовые решения в виде библиотек на PHP? Искал, но не нашел

Guzzle
Ответ написан
@danSamara
У вас IO-bound задача, а это значит:
  1. Вам нужно асинхронное решение, которое позволит избавится от времени ожидание IO операций в основном цикле программы.
  2. Необходимо знать максимальное время обработки ответа (назовём его response_processing_time).
  3. Необходимо знать минимальное время запроса (timeout) - время, в течении которого удалённый сервер не оборвёт связь (пусть будет request_time_out).

Последние два параметра связаны: response_processing_time > request_time_out * количество_запросов. То есть, если вы обрабатываете ответ сервера за 1мс или, другими словами обрабатываете 1000 запросов в секунду, это значит, что для тысячи запросов время соединения не должно быть меньше секунды. Для 5000 одновременных запросов - 5 секунд соответственно.
Это ограничение фундаментально и обойти его не получиться - можно только оптимизировать: или железом - задействовать дополнительные ядра процессора и/или программно - уменьшением времени обработки запроса.
Очевидно, что эти расчёты верны только для постоянного потока запросов, если у вас возможны паузы между запросами, то их надо вносить как поправочные коэффициенты.

Касательно сути вопроса - на чём лучше делать, я бы рекомендовал Go - идеальный язык для всяких сетевых штук, можно сказать, это его родная стихия. Тем более, что задача простая и её реализация не должна занять много времени даже для человека, который никогда с GoLang дела не имел.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
xpert13
@xpert13
Full Stack Developer
Для начала хочу сказать, что мой основной стек на данный момент так же РНР. Возможно я в чем то ошибаюсь, так что не стоит воспринимать моё мнение как мнение великого гуру, но я всё таки поделюсь им.

1. Никак. Я на днях копался в каком-то из фреймворков для многопотока PHP типа ReactPHP и под капотом там просто запуск отдельного процесса для каждого потока. Да, там есть оптимизации, которые позволяют жрать меньше ресурсов, но всё равно это выглядит как ресурсоемкий костыль.

2. Я бы выбирал другой язык. Судя по описанию задачи кода там не много, так что переписать будет несложно.
Ответ написан
sergiks
@sergiks Куратор тега PHP
♬♬
Посмотрите на Swoole PHP – он хорошо умеет в неблокирующую асинхронность и корутины. Так сможете в меньшее число тредов запустить неблокирующие curl запросы. Swoole работает со стандартным libcurl – можно тот же GuzzleHTTP использовать.
Ответ написан
Комментировать
Ichi
@Ichi
Увлекаюсь программированием
Можно посмотреть phabel и есть стандартные средства многопоточности у php. Но на столько больших запросах я не проверял (у меня небольшой проектик с несколькими десятками запросов).

Тут скорее всего лучше смотреть в сторону Python или Go. У них подобное гораздо лучше должно работать.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы