Pull to refresh

Пуш ми, бум-бум, тач ми… Ajax Push Engine

Reading time5 min
Views6.9K
logoСегодня поговорим о Comet и о server push вообще.

Обычные веб-приложения, как и сайты, работают по традиционной модели запрос-ответ-запрос, при этом, в силу особенностей HTTP-протокола и некоторых серверных реализаций обработчиков, приложение не хранит информацию между запросами, так что каждый вызов является независимым, а идентификация или сессионность обеспечиваются более высокоуровневыми средствами (например, всем известная реализация сессий в PHP). Кроме этого, запрос на новую информацию посылает всегда клиент, который заинтересован в получении самой актуальной версии данных. В приложениях, которым критично обновление, это часто становиться узким местом. У нас в одном из предыдущих проектов, было сразу несколько периодических AJAX-запросов на обновление данных. Хотя для такого случая есть варианты и вызова нескольких обработчиков на стороне сервера одним запросом от клиента.

ape-cross-browser1


Но существует другой подход, когда сервер самостоятельно определяет, что есть новые данные (а он то узнает об этом самым первым) и доставляет их клиентской программе, которая не тратит время на запросы, а сама получает, когда что-то новенькое появилось. Для этого, правда, необходимо держать постоянным подключение к серверу, например, через двунаправленный сокет. И если в традиционном ПО с этим особых сложностей не наблюдается, что реализовать долгие постоянные соединения для веб-приложений достаточно непросто. Самым примитивным способом это делают через IFrame, однако это не единственная возможность, да и разработчики топовых библиотек и плагинов к ним постарались, так что поищите в своем любимом фреймворке, реализация Comet там должна быть (она точно есть в Dojo Toolkit, есть плагины для jQuery, встроенная возможность в GWT). Также можете почитать о различных способах реализации вот в этом наборе материалов.

А вот как сделать сервер? Обычный вариант Apache + PHP слабо подходит, хотя, конечно, и на нем возможно, но решение будет далеко не оптимальным и не выдержит типичной нагрузки. Кстати, о нагрузке. Для Comet-приложений нагрузкой считается количество клиентов, которые могут быть обслужены одновременно, при этом имеется ввиду количество открытых соединений с клиентами, а не передача данных. И число таких соединений для обычных серверов должно достигать десятков тысяч, типичные цифры — 20 — 50 тыс. соединений параллельно. И вот тут связка Apache/PHP никак не поможет. Надо что-то другое.

Для мира Java есть реализации для серверов приложений, например, Jetty (наверное, самая известная и стандартная реализация Comet, вот хорошая статья на русском от IBM), не так давно появился серверный фреймворк на базе платформы GrizzleAtmosphere, так что реализовать собственную логику и свой сервер для специфического приложения не составит труда.

Остальным что делать? Им могу порекомендовать открытый проект APE или Ajax Push Engine. Это небольшой сервер, написанный на С, который компилируется в виде демона и слушает свой порт, по умолчанию, 6969, однако его можно настроить и на совместную работу с Apache. В отличие от других решений, APE это специализированный HTTP-сервер, который поддерживает GET/POST запросы, то есть, подключиться к серверу можно с любого языка и системы, лишь бы понимались HTTP-запросы. И это самодостаточно решение, в принципе, можно ограничится одним только APE, без дополнительных серверов (в Jetty реализация все же требует сервера приложений и веб-сервера). По заявлениям разработчиков, APE отлично работает под нагрузкой и способен держать одновременно до 100 тысяч соединений, в дальнейшем будет добавлена и горизонтальное масштабирование.

ape-how-it-works


Следует заметить, что по своей архитектуре, проект APE состоит из трех частей:
  • epoll-driven HTTP server — самая основа, сервер, который обрабатывает подключения и держит соединения, позволяя реализовать Server push любым подходящим для клиента образом, будь то XHR long-polling или через iframe, а в будущем и нативные возможности браузеров будут утилизированы (например, web sockets)
  • APE JavaScript Framework — не менее важная часть проекта, клиентский скрипт на базе MooTools, который может интегрировать возможности сервера в любое клиентское AJAX-приложений. Также в нем реализована модульная система и расширения, так что поверх можно написать любую обертку для другой библиотеки или прозрачно встроить в ваше решение. Библиотека реализует имитацию сокетов и pipe, так что разработчик получает достаточно высокоуровневые абстракции, а если забраться еще выше, то ему доступна событийная модель и можно просто забыть о деталях реализации.
  • Система плагинов — сервер можно расширять, добавляя собственную функциональность через подключаемые модули. Сейчас доступно только через С-модули, однако они предельно просты, в будущем ожидается серверный JavaScript, что станет по истине отличным решением (эх, ещё бы РНР туда прикрутить, хотя, конечно, можно через простенький C-плагин, но все же).

На стороне сервера, APE использует механизм epoll, а также реализацию хеш-таблицы (DJB Hash Algorithm). Это оборачивается, кроме максимальной производительности, ещё и сложностями в портировании — сервер хочет для сборки ядро Linux 2.6.19+ и libc6-dev, и пока заставить его собираться под Cygwin мне не получилось (стопор именно в плане epoll-механизма, встроенного в ядро).

Для обмена информацией между сервером и клиентом, а также между клиентами (через сервер), в APE реализовано несколько методов. Первый — каналы (Channels), когда пользователи подписываются на определенные каналы, а когда на сервере появляется новая информация, ассоциированная с этим каналом, она передается всем клиентам, слушающим канал. Таким образом можно сразу разослать новые данные всем клиентам, которых может быть неограниченное количество. Также APE можно использовать как очередь сообщений, хранимых в памяти — каждый подключенный пользователь имеет одну или несколько очередей. Получателем сообщения может быть или канал, тогда сообщение получат все, или напрямую другой пользователь, либо внешний сервис. Каналы могут быть как интерактивными, так и доступными только для чтения.

APE берет на себя роль прокси-сервера, позволяя обмениваться сообщениями с внешними сервисами (например, вашим сервером приложения), а также получать от них данные и рассылать их в каналы или конкретным пользователям. Таким образом, можно построить систему, в которой фронт-ендом для пользователей будет APE, который обрабатывает подключения, а дальше работает уже бек-енд сервер, поставляющий и принимающий данные в виде сообщений по внутреннему протоколу APE, однако ничего не знающий о количество подключенных клиентов, ему надо только уметь общаться с APE-сервером.

ape-communication-system


Взаимодействие между клиентом и сервером производится через специальный протокол. Пользователи могут инициировать команды, например, послать сообщение или создать подключение, в ответ на которые сервер шлет RAW-данные, обычно это JSON. Однако модули сервера могут расширять встроенный набор команд, поэтому вы можете описать собственный набор действий, в зависимости от потребностей.

Хотя официальная документация все еще в разработке (конечно, это вики), и не сообщает о доступных модулях, в репозитарии исходников доступны несколько базовых модуля, которые могут пригодится и как справочное пособие для разработки своих решений, так и для встраивания в уже существующую инфраструктуру. Например, libape-mysql позволяет подключаться к базе данных и получать оттуда новую информацию (однако, учтите, что версия модуля 0.01), а libape-chat покажет демо-версию простой чат-системы. Самым интересным обещает быть libape-spidermonkey, хотя пока о нем нет никакой информации, кроме исходника.

Проект очень молодой, однако уже показывает свой потенциал, поэтому если вы планируете начинать какое-либо серьезное приложений, где требуется одновременная работа с множеством пользователей (чат или игровая система), или критична доставка данных, советую обратить внимание на APE.

P.S. Если кому получится собрать этот сервер под Win32 систему — пожалуйста, поделитесь решением!
Tags:
Hubs:
Total votes 51: ↑43 and ↓8+35
Comments34

Articles