М 10 Теория. Comet и Pub Sub. ActionCable - Evanto/qna GitHub Wiki
Технологии Comet и Pub/Sub и их реализации на фреймворке Rails ActionCable.
Comet
Comet - технология, которая позволяет отправлять данные на клиент без запроса со стороны клиента. Т.е. сервер сам решает, в какой момент и какие данные он хочет передать клиенту. Альтернативное название этой технологии - Push технология, в противовес Pull-технологиям - таким, как Ajax, которые, в свою очередь, стягивают данные с сервера в отличие от Comet, в котором сервер пушит данные на клиент.
Comet - это:
- Push-технология
- Позволяет отправлять данные на клиент без запроса со стороны клиента
- Работает в реальном времени
Comet vs Ajax
История возникновения названия Comet: Comet - 2-5 по популярности средство для чистки в Америке после Ajax.
- Comet: передача данных только с сервера на клиент
- Ajax: клиент посылает запрос, сервер отвечает на запрос.
Технология Publish/Subscribe (Pub/Sub) - это:
- Модель взаимодействия клиента и сервера по технологии Comet
- Сервер предоставляет именованные каналы
- Клиент подписывается на один или несколько каналов
- Сервер отправляет данные (сообщение) в канал
- Все клиенты, подписанные на канал, получают это сообщение
Pub/Sub - это конкретная модель взаимодействия клиента и сервера по технологии Comet. Comet только значит, что мы отправляем данные на клиент без какого-либо запроса (что это Push-технология). Pub/Sub - это уже конкретная реализация данного подхода. Обычно Pub/Sub основан на следующих идеях:
Сервер предоставляет именованные каналы (канал А, канал Б, etc) - каналы связи, по которым он хочет отправлять данные. Клиент может подписаться на один или несколько каналов, которые ему нужны. Сервер ничего не знает о клиентах, он просто передает данные в канал, и клиенты, которые подключенные к этим каналам, просто получают сообщения (данные, передаваемые по каналам, называются сообщениями.
Исторические технологии (предвестники Pub/Sub)
У технологий Comet и Pub/Sub довольно большая история. Какие существуют исторические технологии (которые использовались 5-10 лет назад)? Прежде всего это технологии, основанные на Flash. Сейчас все отказываются от flash-технологий, и постепенно они уходят из браузера, но именно они были первыми попытками сделать Comet в браузере, используя либо flash-сокеты, либо протокол RTMP, который поддерживается flash-медиа сервером от Adobe, которые, как правило, использовали для конференций и передачи потокового видео.
Исторические технологии - предвестники Pub/Sub:
- Flash-технологии (FlashSocket, RTMP)
- Short Polling
- Бесконечный iframe
Short Polling - это типа тот же Ajax, просто клиент постоянно запрашивает данные, сервер лишь следит за хранением истории сообщений для конкретного клиента и отдачей их ему, если они появляются в очереди. Это нельзя назвать по-честному Comet-технологией, т.к. клиент все равно делает запрос.
Бесконечный iframe - довольно интересный исторический вариант реализации Comet: на страницу вставлялся iframe (а мы можем передавать данные с внутреннего фрейма в родительский через js). Этот iframe отдавался серверу бесконечно долго, и сервер не закрывался (не завершал передачу тела страницы), а просто добавлял туда новые строки с выполнением какого-то js, который, в свою очередь, отправлял сообщение в родительское окно. Сейчас такой подход (как и другие исторические технологии) уже не используют, т.к. появились более современные альтернативы.
Современные технологии реализации Comet
- Long Polling
- Server Sent Events
- WebSockets
Long Polling - как в Short Polling, взаимодействие тоже отчасти инициируется на клиенте (клиент делает запрос), но сервер не отвечает сразу, а держит соединение открытым какое-то время и, если в этот промежуток времени необходимо отправить клиенту сообщение (происходит какое-то событие), от тут же отправляет ответ обратно клиенту, а если его не происходит, то ждет еще определенное время (тайм-аут), после которого клиент заново отправляет запрос и также долго ждет.
Server Sent Events - довольно новая технология, стандарта HTML-5, которая позволяет клиенту отправить запрос 1 раз на какую-то страницу (н какой-то адрес на сервере), после чего сервер может сколь угодно долго работать с этим запросом и отправлять него данные. Отчасти это похоже на бесконечный iframe, но сделанный не через костыли, а по-нормальному. Но там есть свой нюанс, который мы обсудим позже.
Рассмотрим эти 3 технологии подробнее. Long Polling Схема взаимодействия клиента и сервера технологии Long Polling:
В первом случае (вверху) клиент делает запрос (как правило, это GET-запрос) на адрес poll, и, пока на сервере не возникнет событие (event), клиент не получает ответ. Как только возникло событие, которое нужно отправить клиенту, сервер тут же отправляет ответ, после чего клиент сразу делает новый запрос на poll и ждет.
Во втором случае (ниже) никакого события не произошло, но вышло время (timeout). Время таймаута настраивается, обычно его делают небольшим - не больше минуты. В случае таймаута клиенту возвращается пустой ответ и заново идет еще один запрос на poll. Хороший пример лонг поллинга - это форум Disqus. Если открыть веб-консоль и посмотреть запросы, увидите постоянные запросы poll, в ответ на которые постоянно приходит какая-то инфа - например, что вам пришло новое личное сообщение что вам пришел ответ на ваш коммент в треде.
Server Sent Events
Тут тоже клиент делает 1 раз запрос, как правило GET (по сути, инициирует/открывает канал), после чего сервер при необходимости отправить данные клиенту отправляет данные в это подключение. Есть инициация подключения, после чего сервер отправляет сообщения по событиям. Технология очень простая в реализации, например с точки зрения Rails это отдельный контроллер и 1 экшен, в котором можно делать, что угодно: отправлять данные на клиент и т.д. Но у этой технологии есть один большой минус: она вообще никак не поддерживается интернет эксплорером (даже последних версий). Именно поэтому она редко используется (т.к. На эксплорере сидит довольно много людей, и для них придется использовать другую технологию, и зачем тогда две, если можно взять другую).
WebSockets
Эта технология подразумевает открытие подключения к серверу (серверу посылается запрос на подключение, сервер при готовности от отправляет ответ со статусом open, т.е. открывает соединение, и тогда по нему можно отправлять сообщения - в любую сторону, в любом порядке, асинхронно - нет никакой связи между сообщениями, идущими в одну и в другую сторону). WebSockets - технология двустороннего общения клиента и сервера, т.к. по 1 подключению данные передаются в обе стороны, и сервер может обрабатывать сообщения от клиента. Можно и вместо Ajax использовать WebSockets (но это будет сложно с точки зрения придумывания логики, как на стороне клиента, так и на стороне сервера, хотя и есть такие эксперименты - например, WebSocket REST).
Реализации и библиотеки
Какие есть конкретные реализации и библиотеки для каждой из 3х технологий, которые мы только что рассмотрели? Ruby/Rails
- MessageBus - Long Polling (часть движка Disqus)
- Faye (PrivatePub) - WebSockets, Long Polling
- ActionCable - WebSockets *Другие (OSS) - опенсорс решения
- Socket.io (NodeJS)
- Crossbar.io (Python) PaaS (по подписке)
- Pusher.io
- Pubnub.com
- ably.io
MessageBus - детище Сэма Сэффрона, автора Disqus, который топит за лонгполлинг и известен статьей “Осторожно, веб-сокеты!”, где аргументирует свой выбор лонг полинга перед веб-сокетами:
WebSockets, caution required (Sam Saffron)
WebSockets: caution required (on HN)
Сервер Faye - есть реализации на Ruby и Node.js. Для Rails есть обвязка PrivatePub, позволяющая удобно интегрировать вебсокет-сервер в приложение. Она поддерживает вебсокеты и лонг поллинг.
ActionCable позволяет работать только с вебсокетами (это минус, т.к. Не все браузеры поддерживают веб-сокеты, например эксплорер поддерживает их только с версии 10).
PaaS-ы при покупке подписки через API и клиентские скрипты возьмут за вас на себя всю заботу о риалтайм взаимодействии в вашем приложении. Как правило все используют вебсокеты и имеют коллбеки на лонгполлинг. Самый известный из этих Paas - pusher.io, и есть 2 менее популярных: pubnub и ably.
ActionCable
Мы будем использовать ActionCable (почему):
- Встроен в Rails 5
- Каналы - доступ к бизнес-логике приложения
- Стримы - реализация pub/sub
- Возможность обмена сообщениями клиент-сервер через кабель
ActionCable - фреймворк, встроенный в Rails 5. После rails new у вас уже есть все необходимое, чтобы использовать ActionCable. В нем есть несколько основных элементов логики, в первую очередь каналы. Каналы - это не каналы pub/sub, по которым перемещаются сообщения, а аналог контроллеров для веб-сокетов, некое описание бизнес-логики приложения для веб-сокетов. Можно ограничивать доступ к каналам (к каким-то частям бизнес-логики) и реализовать подписки на стримы, которые являются частью логики pub/sub. Стрим - это именованное соединение (канал). Клиент может подписываться на каналы и получать от них сообщения.
Рассмотрим ActionCable на примере нашего приложения и добавим в него риалтайм-взаимодействие.