Страницы

Поиск по вопросам

понедельник, 4 марта 2019 г.

Постоянное подключение на PHP со свойствами LongPolling и WebSocket

LongPolling работает так, что клиент подключается к серверу по протоколу http(s) и зависает, пока сервер не ответит. После этого создается новое подключение. Это подключение происходит абсолютно стандартным образом с отправкой всех заголовков и cookie. Для каждого такого подключения апач (или другой сервер) создает изолированный процесс.
WebSocket в свою очередь подключается к специальному серверу по отдельному протоколу ws(s). Выходит, что есть всего один процесс, в котором должна проходить авторизация, и велика вероятность утечек памяти. Но преимущества этого подхода в том, что есть постоянное подключение, что обеспечивает моментальную реакцию на события. Помимо прочего, в случае работы с WS не обязательно хранить сообщения где-то в БД, чтобы ничего не было потеряно при переподключении.
Вопрос вот в чем: есть ли что-то среднее между LP и WS?
Работает по протоколу http(s) со всеми плюшками (headers и cookies) Можно написать простой PHP скрипт, который будет запускаться по запросу и обрабатывать все эти подключения, а не пилить полноценный WS сервер, который нужно будет еще мониторить и следить за тем, чтобы он правильно работал. (P.S. Я в проекте единственный разработчик/дизайнер/верстальщик/сис.админ/другое слово, поэтому не хочется добавлять себе еще хлопот) Для каждого подключения спаунит отдельный процесс, изолированный от других подключений Имеет постоянное подключение. И чтобы можно было отправлять сообщения хотя бы в одну сторону (сервер => клиент)

Подробнее о том, в чем собственно проблема.
В проекте используется framework Yii2 с местной системой авторизации и со всеми его плюшками. Описанный мною подход позволил бы мне аутентифицировать пользователя встроенными в framework методами, а саму логику внедрить в action контроллера.
В противном случае мне нужно будет написать отдельный сервер или использовать готовое решение и как-то интегрировать его с фреймворком.
Смотрел в строну Workerman. Опять же возникает вопросы аутентификации, поддержки сервера в рабочем состоянии при утечках и крашах (supervisord?), перезапуска при деплое
Если я где-то заблуждаюсь, тыкните, пожалуйста, пальцем.


Ответ

Достойных альтернатив для WebSocket в наше время считайте что нет. Или WebSocket, или всевозможные костыли. Если без костылей, то...
Первое, что нужно сделать: настроить nginx для передачи WebSocket соединений дальше по цепочке. Так, все ваши клиенты будут работать с nginx, а не напрямую с вашими другими про­граммами. Сохраняются и используются все достоинства nginx. Не нужно использовать выде­ленный порт. Не нужно настраивать HTTPS дважды. Не нужно перезапускать какие-то другие про­граммы после обновления сертификатов Let's Encrypt.
Настройка делается в четыре строчки:
location /mywsapp { proxy_pass http://mywsbackend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
Дальше, нужна альтернатива самостоятельной обработке входящих соединений WebSocket. Такая программа будет брать на себя обработку входящих WS соединений во всей их слож­ности, оставляя вам лишь обработку входящих сообщений и отправку исходящих.
websocketd
Например, программа websocketd работает как inetd, только для процессов. При новом соеди­нении запускается ваша программа, которой нужно читать стан­дартный вход и писать в стан­дартный выход. Можно не читать, только писать. Пример использования в другом ответе.
"; }
Всевозможные заголовки, которые отправляет ваш клиент, доступны через переменные окру­жения. Например, куки видны в $_ENV['HTTP_COOKIE'] и так далее.
Вашим требованиям в части запуска процесса по факту подключения этот подход соответ­ствует. Есть недостатки: если вам повезёт вырасти до сотен или тысяч одномоментных под­ключений, то это будет означать сотни и тысячи висящих в памяти процессов PHP. Впрочем, об этом можно будет подумать потом.
Кроме ограничений по памяти, постоянно работающие процессы PHP создают ещё одну проблему: если вам захочется обновить их логику, то вам потребуется механизм отключения всех таких процессов.
nchan
Если забыть про некоторые требования, то модуль nchan для nginx может ещё больше аб­стра­гировать работу с сообщениями. Для каждого подключающегося клиента вы выделяете какой-то длинный и секретный ID (что-то типа номера почтового ящика), по которому тот подключается к nchan и ждёт сообщения. Вы, со своей стороны, по этому же ID отправляете сообщения по простому HTTP. Если у вас появится больше одного сервера, то забирать сообщения nchan может из Redis.
Установка проще не может быть:
sudo apt install libnginx-mod-nchan
Пример конфигурации.
Недостатки: увеличенная сложность конфигурации nginx и всей архитектуры системы, необходимость хранить идентификаторы клиентов за пределами $_SESSION.
Достоинства: не нужно для каждого соединения держать процесс PHP.

Список будет пополняться.

Комментариев нет:

Отправить комментарий