Websocket′ы полезны постоянным дуплексным соединением backend-сервера с браузером клиента — это прочный мост между сервисом и посетителями, по которому удобно беспрепятственно транспортировать потоки данных в обе стороны.
В результате внедрения websocket′ов наш проект получил возможность в реальном времени менять по своему усмотрению отображение страниц в браузере на протяжении всей клиентской сессии и иметь обратную связь.
В ходе построения всей технологической цепочки мы легко перешагнули через проблемы с браузерами, лишь изредка не поддерживающими либо сами websocket′ы, либо их эмуляцию через flash.
Однако, когда дело дошло до полевых испытаний, обнаружилась масса проблем с ISP, всеми мыслимыми и немыслимыми способами пытающимися сэкономить трафик за счёт своих клиентов. Об этих и других «граблях» полноценного боевого внедрения websocket′ов читайте под катом.
К примеру, в московском офисе нашей компании proxy-сервер ISP (самый крупный в Москве) вырезает заголовки websocket handshake. Таким образом, 80 % наших усилий было потрачено на разрешение мирным способом именно этих проблем.
Но есть и хорошие новости: построенная связка технологий сейчас уже находится в режиме бета-тестирования. Мы учимся контролировать все звенья технологической цепочки от выпадения — это вопрос администрирования, на котором мы всё туже затягиваем гайки. Мост наведён, вытянут в струнку и ждёт первых посетителей.
Вот краткая хроника решения проблем на этапе внедрения.
- Mojolicious не может работать в production с использованием Mojo::Server::Daemon: неустойчивое поведение на больших нагрузках (подвисания, утечки памяти, потери коннектов). Зато отлично себя чувствует на Mojo::Server::Hypnotoad.
- Safary на iPhone (iPad, iPod) использует WebSocket76, который Mojolicious уже не поддерживает. Решением стал написанный нами модуль MojoX::Transaction::WebSocket76.
- Хитрости ISP с клиентским трафиком победило решение SockJS.org, эмулирующее websocket′ы различными транспортами: xhr-streaming, xdr-streaming, iframe-eventsource, iframe-htmlfile, xhr-polling, xdr-polling, iframe-xhr-polling, jsonp-polling.
- SockJS c Mojolicious соединён через допиленный SockJS-Tornado. Допилить пришлось с использованием python модуля WebSocket к нему асинхронную работу не только на внешний канал, но и на внутренний.
- Специально для наших «любимых» ISP транспорт websocket′ов работает по 80-му порту (так как все остальные порты никак от блокироки ISP не защищены). Выделили ip-шники и субдомены для клиентских сайтов.
- Сессионные данные храним в MemCache.
- Транспортом общения выбран JSON RPC 2.0 + HTML::FormHandler + DBIx::Class. Все запросы к серверу — полноценные формы, ответом на которые могут приходить ошибки. Их многоязычность реализована через gettext.
- Как отдельные «грабли» (хотя и незначительные) стоит назвать необходимость обрабатывать на уровне js русскоязычные домены с использованием punycode.
- Мы реально пингуем браузеры клиентов. У нас есть пинги, в ответ на которые мы принимаем понги.
Получившаяся схема обеспечивает 100%-ное покрытие всех пользователей. Смотреть плоды внедрения можно на любых сайтах, построенных на setup.ru, — websocket′ы в режиме бета-тестирования используются для форм обратной связи («ушко» «Задать вопрос») и корзины интернет-магазина.
Ссылки по теме:
- Википедия про вебсокеты
- Project Mojolicious
- Project SockJS
- Perl module MojoX::Transaction::WebSocket76
- Perl module Mojo::Server::Hypnotoad
- Python module SockJS-Tornado
- Python module WebSocket
- Конструктор сайтов Setup.ru
Автор: dsimonov