SendGrid для PHP работает медленно. Возможны ли неблокирующие запросы?
В настоящее время мы разрабатываем мобильное приложение для iOS и Android. Для этого нам нужны стабильные веб-сервисы.
Требования: - Основано на PHP и MySQL, должно быть быстрым, должно быть масштабируемым
Я создал пользовательские простые веб-сервисы с несколькими конечными точками, которые позволяют передавать данные из приложения в нашу базу данных и наоборот.
Мой вопрос:
наше среднее время отклика с моим заказным кодированным решением составляет менее 100 мс (измеряется с помощью newrelic) для обычных запросов (скажем, обновление поля БД или выполнение INSERT INTO). Это без какой-либо нагрузки (менее 100 пользователей в день). Когда мы создаем исходящие запросы (в частности, отправляем E-Mail с использованием SendGrid PHP-Framework), мы видим время ответа> 1000 мс. Похоже, что запрос "ожидает" ответа от Sendgrid. Можно ли сказать сценарию "не ждать ответа"? Это не совсем идеально. Моя идея состояла в том, чтобы сохранить все "ожидающие" запросы в отдельной таблице, а затем с помощью cron выполнить все "ожидающие" запросы и пометить их как "выполненные". Это жизнеспособное решение? И будет ли достаточно одного крона в минуту для обработки запросов (возможная задержка в 1 минуту для каждой электронной почты)?
Как всегда, любые ответы или предложения очень ценятся. Заранее спасибо!
2 ответа
Чтобы ответить на первую часть вашего вопроса: Да, вы можете делать асинхронные запросы с PHP и даже игнорировать ответ службы. Однако, как вы правильно сказали, это не супер-отличное решение.
Асинхронные Запросы
Этот отличный пост в блоге об асинхронных запросах PHP от Segment.io приводит к нескольким выводам:
- Вы можете открыть сокет и записать в него, как описано в этой теме переполнения стека - однако, похоже, что это на самом деле блокировка и довольно медленная (300 мс в их тестах).
- Вы можете записать в файл журнала и затем обработать его другим способом (по существу, очередь, как вы описали). Однако для этого требуется другой процесс, чтобы прочитать журнал и обработать его. Использование файловой системы может быть медленным, а общие файлы могут вызывать всевозможные проблемы.
- Вы можете разветвить запрос cURL - однако это означает, что вы не ожидаете ответа, поэтому, если SendGrid (или какой-либо другой сервис) отвечает с ошибкой, вы не можете его перехватить и отреагировать.
Мнение Земли 
Сейчас мы входим в землю с полу-мнением, но очереди, как вы описываете (такие как mySQL с заданием cron, или текстовым файлом, или чем-то еще), имеют тенденцию быть очень масштабируемыми, так как вы можете бросить рабочих в очередь, если вы нужно, чтобы обрабатывать быстрее. Они могут находиться за пределами вашей системы, обращенной к пользователю (и, следовательно, не делиться ресурсами).
Очереди
При наличии очереди у вас будет отдельный сервис, который будет отвечать за отправку электронной почты с помощью SendGrid (например). Это вытащит задачи из очереди (например, "отправит электронное письмо Нику") и затем выполнит их.
Есть несколько способов реализовать очереди, которые вы можете обрабатывать.
- Вы можете написать свой собственный - так как вы, похоже, хотите остаться на PHP/mySQL, если вы сделаете это, вам нужно будет учитывать кучу проблем с очередями и странные крайние случаи. Тем не менее, вы будете иметь абсолютный контроль, и для простого приложения, возможно, это будет работать.
- Вы можете реализовать собственную очередь задач - Celery предназначен для распределенной очереди задач, а MQ (ZeroMQ) и RabbitMQ также могут использоваться в качестве очередей задач. Они предназначены для того, чтобы быть быстрыми и распределенными, и в них было вложено много мыслей. Вам нужно сравнить их в своей системе, чтобы увидеть, ускорят ли они это. Это также означало бы, что вам придется самостоятельно размещать дополнительные произведения. Однако это, вероятно, будет самым быстрым решением с точки зрения связи.
- Вы можете передавать вещи в очередь размещенных задач - IronMQ и Amazon SQS являются отличными решениями, размещенными на хосте, что означает, что вам не нужно выделять для них ресурсы, кроме того, с помощью IronWorkers (например) вы могли бы позаботиться о другой службе. Однако, поскольку вы пытаетесь оптимизировать запрос к внешней службе, это, вероятно, не решение в этом сценарии.
Очередь писем
Что касается очереди электронных писем (в частности), это нечто общее для отправителей электронной почты. Как и во всем остальном, это означает, что вы можете повысить надежность (потому что, если служба не работает, вы можете оставить ее в очереди и повторить попытку).
С электронной почтой, однако, есть некоторые специальные службы для очередей сообщений. Это SMTP-серверы. Теоретически вы можете настроить сервер, такой как sendmail, а затем установить SendGrid в качестве "интеллектуального хоста" или ретранслятора и отправить сервер в SendGrid. Затем он ставит в очередь и обрабатывает прерывания обслуживания и отправляет почту с небольшим дополнительным кодом. Однако с SMTP-серверами приходится сталкиваться с трудностями, даже если они просто пересылают сообщения. Кроме того, SMTP даже медленнее, чем HTTP, устанавливает соединение, и поэтому, вероятно, не то, что вам нужно, но это полезно знать.
Другое возможное решение, если вы контролируете свою собственную серверную среду, которая ускорит отправку электронной почты, а ваше приложение - это локальная установка почтового сервера, такого как Postfix. Затем вы настраиваете Postfix для использования ваших учетных данных Sendgrid, поэтому любое отправленное письмо будет отправлено с вашего сервера на sendgrid.
Это не решение PHP, но устраняет необходимость написания собственного решения для клиента. Если вы установите Postfix в качестве почтового сервера по умолчанию. Затем вы можете просто использовать функцию php mail() для отправки электронной почты.
https://sendgrid.com/docs/Integrate/Mail_Servers/postfix.html