Javascript.RU

Передача данных по инициативе сервера, обзор COMET

Update: Более новый материал по этой теме находится по адресу https://learn.javascript.ru/xhr-longpoll.

COMET-технологии позволяют организовать обновление данных на странице без участия пользователя.

Чаты, интернет-почта и многопользовательские админки - далеко не полный список, где они применимы.

В этом цикле статей - подробно описаны многочисленные тонкие моменты и решения частых проблем.

COMET (или "server push") - способ передачи данных с сервера на клиент, по инициативе сервера.

Например, у вас есть электронный магазин, и менеджер может отслеживать переходы клиента.
COMET позволяет менеджеру тут же, онлайн, спросить клиента о чем-то, предложить интересный вариант.

"По инициативе сервера" означает, что клиент сам не запрашивает сервер, он просто находится на странице.

Старейший пример COMET - чат. Человек просто находится на странице и получает новые сообщения.

Также COMET используется в админках для оповещения об изменениях со стороны других посетителей, для совместного редактирования документов и т.п.

Способов реализации COMET достаточно много. У них - самые разные характеристики, достоинства и недостатки.
Есть два основных класса.

Каждое событие на сервере браузер получает отдельным запросом. Здесь есть два основных метода.

  1. Частый опрос (polling)
  2. Длинный опрос (long-poll)

Чтобы уменьшить количество необходимых соединений и задержки, сообщения о событиях пакуют в специальные пакеты, "датаграммы".
Например, одно XML-сообщение может выглядеть как:

<events> 
  <message> 
    <from>Vasya</from> 
    <text>Привет!</text> 
  </message> 
  <notification> 
    <type>processing</type> 
    <text>Обработка завершена</text> 
  </notification> 
</events>

При очередном подключении браузер получает сразу весь пакет событий к настоящему моменту.

Браузер держит постоянное соединение с сервером, так называемый "канал", и получает через него события.

Канал связи разрывается время от времени:

  • чтобы прокси не подумал, что настал таймаут соединения и не порвал его за нас
  • для очистки памяти от мусора старых сообщений

Кроме того, для измерения сетевых задержек и контроля соединения, сервер может периодически посылать по этому каналу ping-пакеты.

  1. Бесконечный IFrame
  2. XMLHTTPRequest, interactive
  3. Multipart XMLHTTPRequest
  4. Event-source

Вы найдете их в других статьях этого раздела.

Протокол HTTP изначально создавался так, чтобы один запрос возвращал одну единицу информации. А мы хотим - много, отсюда и некоторые сложности...

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

Решение - добавлять к каждому сообщению 2K пробелов.

Неизвестно, коснется ли Вас эта проблема. Надеюсь, что нет, но иметь в виду буферизацию прокси как возможную причину жалоб пользователей - надо обязательно.

IFrame, который служит для передачи сообщений, НЕ должен сжиматься gzip/deflate. Иначе говоря, для служебного URL сообщений сжатие должно быть отключено.

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

Это - неприятное последствие хакерской натуры iframe. Например, в long poll сжатие проходит на ура, т.к события не являются частью одной страницы.

Не забудьте отключить буферизацию сервером. В связке Apache/PHP - отключите output buffering и включите ob_implicit_flush:

while (@ob_end_flush()) {}
ob_implicit_flush(1);

// ну и конечно убрать лимит на время выполнения скрипта
set_time_limit(0);

Как всегда, при написании веб-приложения встает вопрос о выборе архитектуры. С одной стороны, решения на длинных соединениях (все, кроме частых опросов) обеспечивают быстрое уведомление. С другой... Всегда ли длинное соединение лучше частых опросов?
Решение с длинными соединениями с виду оптимальнее, но гораздо сложнее и обладает рядом особенностей.

  1. Реализация длинного коннекта, как правило, усложняет архитектуру. Возможно, можно обойтись решением попроще?
  2. Ряд веб-серверов плохо оптимизированы под большое количество длинных соединений. Например, используются потоки или процессы, которые отъедают фиксированное количество ресурсов и не освобождают их до конца соединения.На уровне OS проблема решается использованием kqueue(FreeBSD) или epoll(Linux).На уровне веб-сервера можно использовать
    1. Apache MPM event для apache 2.2 (экспериментальный и ограниченный MPM, специальный поток обрабатывает Listening и Keep-Alive сокеты)
      не работает как следует с mod_perl/mod_php
    2. Jetty (Java) / Twisted(Python), nginx и другие специализированные серверы c одним потоком/процессом на много клиентов.

    Потянет ли текущая серверная архитектура длинные соединения? Ответ неочевиден для сотен/тысяч одновременных соединений, но, скажем, до 100 соединений в любой архитектуре все хорошо.

  3. Насколько долго пользователи находятся на одной и той же странице? При переходах коннект, скорее всего, придется открывать заново в любом случае.
  4. Если допустимы задержки доставки событий, то, может быть, хватит частого опроса?

Посмотрим на взаимодействие клиент-сервер "с высоты птичьего полета", выше деталей передачи данных, транспортов и т.п. Например, так это сделано в специализированном server-push движке lightstreamer.

Соединения с сервером делятся на два типа

  1. Control connection - контрольные соединения, через которые клиент отправляет запросы на сервер. Это - обычные AJAX-запросы через XMLHTTPRequest.
  2. Push connection(channel) - поток событий, соединение, через которые клиент получает события с сервера

У всех событий на сервере есть тип. Клиент может подписываться и отписываться на интересующие его события через контрольные соединения. Для удобства типы организованы по схемам. Например, в схеме chat может быть тип message.

Например, следующая диаграмма описывает типичную последовательность действий:

  1. Клиент открывает потоковое соединение к серверу
  2. Клиент подписывается на события типа Item1 в схеме Schema1
  3. Сервер шлет события
  4. Клиент отписывается от событий через новое контрольное соединение
  5. Клиент закрывает соединение

Или - вот более сложная диаграмма, в которой клиент подписывается уже на разные типы событий:

В качестве транспорта в lightstreamer используется iframe. Время от времени его необходимо закрывать для очистки от принятых объектов. При закрытии сессии (это же происходит при refresh страницы в браузере) сервер буферизует новые события до некоторого таймаута и отдает их, как только открывается новая сессия Stream Connection 2 того же пользователя.

Вообще, буферизация событий - общий прием, который позволяет мягко переживать закрытие соединения, и нужен при любом транспорте.


Автор: OS master (не зарегистрирован), дата: 4 сентября, 2008 - 01:52
#permalink

Скажите, а как при помощи mpm event решить вопрос создания апачем файлов от юзеров, которым принадлежит папка, в которой работает скрипт, а не nobody.
Спасибо!


Автор: Илья Кантор, дата: 4 сентября, 2008 - 08:15
#permalink

Вообще-то это не по теме, но все равно ответ - никак


Автор: Анатолий (не зарегистрирован), дата: 2 декабря, 2008 - 21:34
#permalink

неужели в этом можно разобраться?


Автор: Илья Кантор, дата: 3 декабря, 2008 - 11:30
#permalink

Изображения вверху записаны в UML-нотации. Конкретнее - это диграммы последовательности (sequence diagram).

Возможно, проще (и полезнее) - разобраться сначала с sequence diagram в UML вообще, а потом - в конкретными диаграммами здесь.


Автор: Гость (не зарегистрирован), дата: 6 января, 2010 - 16:07
#permalink

А сорс есть?


Автор: dima0000 (не зарегистрирован), дата: 16 марта, 2010 - 09:48
#permalink

я хотел бы написать на perl такой чат c jquery

можете ли вы подсказать как в этом разобратся?
нужно написать демона на сокетах? как это все будет?


Автор: Valery (не зарегистрирован), дата: 31 августа, 2010 - 16:45
#permalink

Илья,

Есть ли у Вас информация о том какие из методов используют большие компании вроде Facebook (чат, оповещения), Gmail (чат), Twitter (notifications)?


Автор: Илья Кантор, дата: 31 августа, 2010 - 20:32
#permalink

Добрый день!

Facebook - Tornado (их разработка, Open Source, Python), Gmail - свой сервер, клиентская часть - open source Google Closure Library, Twitter - не в курсе...

--
Илья


Автор: Гость (не зарегистрирован), дата: 14 октября, 2010 - 21:43
#permalink

Twitter - Erlang и Scala


Автор: Илья Кантор, дата: 15 октября, 2010 - 10:10
#permalink

Источник?


 
Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние темы на форуме
Forum