Pull to refresh

Comments 108

UFO just landed and posted this here
В продакшене нет, но планирую в скором будущем. Там ещё есть слабые места.
UFO just landed and posted this here
Пока в продакшн не внедрили писать особо нечего — нет опыта применения. Как используем — напишу.
Тоже с удовольствие почитаю…

лишь бы не в духе: «99% процентов тем завершается словами, как сделаю отпишу» :)
Понятно понятно, то есть не использовали, но заклеймили велосипедистов? Или если есть APE, то всем остальным можно забыть о comet серверах?
Dklab_multiplexor не претендует на полную универсальность или исключительность (кстати, если знаете аналоги, близкие по простоте к multiplexor-у, пишите в комментариях).

Если есть APE то лучше попробовать поддержать/развить существующий проект. Хотя велосипеды с префиксом в виде инициалов я не запрещаю — не моё право :)
APE далеко не всегда и не везде подойдет.
Ну и заодно почему же не вспомнить Orbited?
UFO just landed and posted this here
Что не умеет демонизироваться? Twisted демон не умеет? RTFM.
Ну и для того чтобы разбрасываться словами «поделка» надо иметь очень веские основания, и главное — привести их.
UFO just landed and posted this here
Если хочешь использовать на продакшене — готовься к тому что 70% системы придётся переписывать. Пробывал добиться от него более-менее вменяемой работы, может копал не глубоко — но от использования отказался.
С радостью прочитаю и оценю сервис созданный на нём, не прощаюсь :)
Странно, что ни разу не прозвучало слово Comet
UFO just landed and posted this here
Соединение так или иначе один фиг закрывается и его надо периодически переоткрывать.
UFO just landed and posted this here
Да, закрывает. Автор, просьба от не знающих perl — сделайте из него comet: ))
Не надо. В данном случае закрытие соединения — это плюс, потому что позволяет упрятать мультиплексор, например, за nginx. А комет вам придётся выставлять наружу в голом виде.
В общем то основным свойством серверов comet является как раз способность держать огромное число подключений и тратить на это дело минимум ресурсов. nginx, как мне кажется, здесь вообще не в тему — нечего тут кешировать или проксировать.
Вместо nginx подставьте любой балансер, который скрывает весь парк машин за одним видимым снаружи веб-адресом. А для комета (в классическом виде) придётся прокручивать отдельную дырку, чтобы он гордо торчал своим comet.host.com:123245.

В общем, лёгкость включения в любую имеющуюся систему, мне кажется, вполне компенсирует небольшое неудобство с «ручным» возобновлением соединения. Тем более, что правильно принимать постоянный комет-поток на клиенте — это тоже ещё научиться нужно. А тут всё стандартно, один запрос на одно сообщение.
Я опять же на то упираю, что ему балансер не нужен.
UFO just landed and posted this here
nginx для проксирования портов с демона на стандартный 80
UFO just landed and posted this here
на практике это решилось с помощью флеш-коннектора, который передает сообщения-фреймы наверх на страничку.
UFO just landed and posted this here
UFO just landed and posted this here
Мультиплексор ищет строчку identifier=* в любом месте передаваемых данных.
как-то не айс.
Ну, это некоторый компромисс между красотой и независимостью от протокола.
Зато протокол может быть совершенно любым: при желании можно прикрутить мультиплексор к SMTP или POP, к примеру. :-)
В если ответ клиенту содержит строчку identifier=?
… она будет проигнорирована. Обрабатывается только самая первая строчка вида identifier=*, а вы ее передаете в заголовке (см. пример). Это безопасно.
вот вопрос мой отпал сам собой — понятно, всегда можно написать identifier=0
В Eserv'е (отечественный pop3/smtp/imap/http/итд сервер) что-то похожее есть. При реализации общих папок в IMAP используется (например, если один пользователь удалил сообщение, то у всех остальных юзеров, подключенных к той же папке, проходит об этом извещение, и их IMAP-клиенты соответственно меняют вид списка сообщений). То же самое в чат-серверах (в Eserv/4 plugin'ы, реализующие IRC и XMPP). В HTTP-сервере это (подписку на извещения между подключениями) тоже можно использовать, используется в частности в веб-мониторинге логов. На одно соединение расходуется порядка 20-100кб, т.е. может держать одновременно очень много. Насчет «сотен тысяч одновременно» — не знаю, я лично не пробовал.
UFO just landed and posted this here
Я про конкретную реализацию в виде отдельного демона.
Ух ты, даже в голову не приходило использовать такой способ для уменьшения нагрузки! Решение опять таки лежит на поверхности, а даже мысли не приходило заставлять клиента ждать ответа от сервера, таким образом удерживая соединение :) Спасибо!
Похожий подход был описан тут.
Только сервер на PHP реализован.
Интересная штука.А, допустим, отправка данных группе подключений не предусмотрена, как я понимаю?
UFO just landed and posted this here
Но тогда, если пользователь состоит в 5-и группах, ему нужно будет держать 6 коннктов, один для себя и 5 для каждой группы с разными идентификаторами. Да и не факт, что сообщения отправятся се группе, если это не предусмотрено сервером.
Ну и логичнее получается использовать STOMP, AQMP проксируя их через, например, Orbited.
Пока не реализована, однако это сделать достаточно несложно: можно разрешить синтаксис вида identifier=abc,def,ght,… — на досуге сделаю.
Спасибо Было бы очень полезно
Выложил. Пользуйтесь на здоровье. :-)
не сложно — так сделайте! очень правильная штука будет!
дык, это решается уже на уровне вашего протокола, или нет?
Я тут недавно удивлялся, почему о Comet на хабре никто не пишет? И вот оно!
UFO just landed and posted this here
Ну это же тонкость. А фактически ключ здесь в передаче сообщения клиенту, в момент когда оно произошло.
не в каждом браузере comet посылает больше одного сообщения за соединение. Следовательно, количество сообщений за соединение не является определяющим фактором
UFO just landed and posted this here
авторы комета говорят, что он кроссбраузерный, и называют кометом даже то, что работает в ие. Вы неправы. А это — комет.
UFO just landed and posted this here
у меня нет доверия в этом плане цитатам не с сайта cometdaily.com — раз. Два: они продолжают называть кометом то, что работает в браузерах, отличных от ff

всё, выхожу из бессмысленного спора
UFO just landed and posted this here
Дети, не ссорьтесь. Я лично использую comet несколько лет *начал еще до того, как его этим словом обозвали). Всё работает, во всех браузерах. В зависимости от ситуации разными способами.
UFO just landed and posted this here
UFO just landed and posted this here
По сути не хватает простенькой JS библиотечки для работы с сервером — чтобы само переподключалось и дергало обработчик по событию: ) Для совсем ленивых чтобы.
UFO just landed and posted this here
Ну тут не вижу переподключения: ) Согласен — реализация много времени не займет.
UFO just landed and posted this here
Я правильно понимаю — это клиентская часть, подключаемая к искомому мультиплексору?
UFO just landed and posted this here
Ага. На досуге выложу некоторый вариант.

На самом деле, там не только разрыв соединения нужно обрабатывать, но и ошибки в передаче данных (мало ли, дисконнект приключится внезапный в середине ответа), а также «лежание» сервера, чтобы он не долбился бесконечно при смерти сервера.
а на словах как вы будите обрабатывать то что сервер «лег»?
Очень интересует сравнение такой технологии с простым Аяксом, при работе на php. Может у кого линк есть или кто опытом может поделится.
А что сравнивать? Тот же аякс. Вы посылаете через XMLHttpRequest с клиента запрос серверу, а сервер в ближайшие 300 секунд должен вам выдать ответ с данными. Если сервер за 300 секунд ничего вам не отвечает устанавливаете соединение повторно. Если сервер ответил, обрабатываете ответ и опять же устанавливаете соединение заново. При этом у вас как бы есть постоянное соединение с сервером. На деле все как обычно. Клиент инициирует обмен данными, затем «забывает» об этом и снова вспоминает когда сервер поймет что ему есть что отдать клиенту. Так как реального постоянного соединения нет, после каждого ответа сервера вы повторяете запрос.
Интересует сколько таких висячих соединений может выдержать сервер и сколько может выдержать тот же сервер клиентов, посылающих запрос обычным аяксом каждые Х секунд.
Сервер может выдержать почти неограниченное число соединений (я проверял на 300 тыс. год назад). На каждой паре слушающий_IP: слушающий_порт может быть не более 65536 соединений (по числу портов; на самом деле, меньше, т.к. часть портов уже используется), но никто же не запрещает добавить 10 ip-адресов или 10 слушающих портов (кстати, насчет увеличения числа слушающий_порт не уверен; поправьте меня, если я ошибся). Кроме того, есть еще ulimit -n (лимит на число открытых файлов в системе), у меня не получилось выставить его больше 1 млн для одного процесса. Ну и есть еще разные лимиты внутри системы, которые можно подкручивать (обычно лимиты OpenVZ: TCPSNDBUF какой-нибудь и т.д.) Нужно заметить, что, если какой-то из лимитов оказываются превышенными, мультиплексор не всегда адекватно об этом сообщает, так что, если у вас это произошло (проводите нагрузочное тестирование вначале!), проверьте первым делом лимиты.
Я никак не могу понять — причем тут слушающий порт и 65535? Мы же используем ОДИН порт!
Это правило логично ложится на исходящие соединения.
Поправьте меня, если я ошибаюсь. Но я встречаю эту тему в связи со своими изысканиями по Comet постоянно, и все мои знания активно протестуют.
TCP-соединение характеризуется парой (ip1:port1) < — (ip2:port2). В нашем случае (ip1:port1) = (1.2.3.4:8088). Соответственно, если ip2 зафиксирован, то port2 может меняться только в диапазоне 0..65535 (на самом деле меньше, ну да не важно). Поэтому на 1 слушающий сокет не может быть больше 65536 коннектов (на самом деле немного меньше). Это так?

Если да, то увеличить число коннектов можно, добавив вариабельности либо в ip1, либо в port1.
> если ip2 зафиксирован, то port2 может меняться
опечатка, я имел в виду
> если ip1:port1 зафиксирован, то port2 может меняться

Но вообще, кажется, я написал бред. :-)
Понял, это верно если мы используем фронтенд! Тогда все сходится — фронту придется иметь несколько IP-адресов.
Интересное решение, как бы замена nginx и php, что бы всё это дело не подвисло от кучи запросов.

Спасибо! Обязательно подключим к текущему проекту.
Дмитрий, спасибо, очень компактное и интересное решение. Немного смущает только «мультиплексор ищет строчку identifier=* в любом месте передаваемых данных». Мало ли что там в данных может быть, уж лучше закрепить конкретный заголовок.

Было бы удобно (и, думаю, не сильно бы усложнило код), если бы клиент мог иметь одновременно НЕСКОЛЬКО идентификаторов. Например, localhost:8088/?identifier=1z2y3x&identifier=1z2y3y&identifier=1z2y3z. И клиенту бы дставлялись сообщения, адресованные ЛЮБОМУ из его идентификаторов. Это бы позволило легко реализовать групповую рассылку в сочетании с персональной. Например, в чате юзер имеет собственный id и id комнаты чата. На первый посылаются сообщения, видимые только ему, на второй — сообщения, видимые всем в этой комнате.
И сразу ещё одно предложение: дополнить линию IN командой на получение текущей статистики демона, как минимум, числа установленных соединений, числа онлайн/оффлайн клиентов. Чтобы можно было его подключать к мониторингу.
Он ищет самое первое упоминание строчки identifier=*. Поэтому, если в IN-линию вы будете посылать ответы с заголовком, включающим identifier (а именно так и приходится делать), то никаких проблем нет, и данные могут быть любыми.

Что касается статистики, то ее можно смотреть в лог-файле сейчас. Если сделать tail -n1 /var/log/multiplexor, то вы как раз и получите такую статистику.
Понятно, а как насчёт групповых id-ов? Можно просто запятыми разделять…
UFO just landed and posted this here
Пару лет назад реализовывал подобный мультиплексор на Java. Благо там реализация синхронной очереди делается в пару десятков строк, достаточно эффективно и надежно. Несколько сотен запросов в секунду не создают тормозов.

Хочу обратить внимание на один достаточно не очевидный момент:

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

При F5 на этой странице имеем реальную возможность потерять сообщение!
(Ладно бы это какой-нибудь чат, у меня стабильно терялось init сообщение :)

Дело в том, что живой XmlHttpRequest заблокированный на сервере не умирает в момент релоада страницы,
и следующее сообщение он вычитает из очереди и доставит, правда уже в никуда, так как его контекста уже нет.
Так как здесь используется метод «запрос — отложенный ответ», то может быть надо в каждом запросе делать подтверждение принятых данных?
Средствами AJAX этого не добиться: когда ответ уходит клиенту, клиент уже не имеет возможности сказать серверу, принял он его или нет. Но вообще, конечно, никто не мешает сделать отдельный AJAX-запрос на сервер, в котором сообщить, что данные приняты, и снова их пересылать не нужно.
Я имел ввиду сделать ACK при следующем запросе. Если ACK не будет — отдать данные по второму разу.
Чего в ней отличного? Это реализация протокола TCPIP получается :)
Ну так как у нас TCP/IP нет, то вот и извращаемся: )
На самом деле можно придумать множество методов, чтобы доставить все нужные данные.

Я просто рассказывал про достаточно не очевидный момент с зомби-XHR, возможно это сэкономит кому-нибудь кучу времени.
UFO just landed and posted this here
У меня было вообще забавно. Схема такая — страница при загрузке шлет серверу «я тут», а сервер регистрит её и начинает в ответ слать данные (у юзера машинка по карте начинает ездить). Все было зашибись пока не пришлось добавить один маленький инит-пакетик перед потоком данных. Выглядит всё здорово — сервер получает «я тут», высылает «инит», его видно в tcpdump, он проходит по логам XHR, но на страницу не попадает, сцуко!

Пришлось вставить reset_queue(), который очищает клиентскую очередь пакетов на сервере и засылает туда для начала «nop», а потом уже «инит» и далее по списку.

«nop» пакет вообще полезен, у меня сервер с интервалом в несколько секунд высылает клиенту «nop» (там еще и серверное время вставлено на всякий случай), а на клиенте поставлен таймаут на XHR побольше, чем на сервере, чтобы ни там ни сям не клинило и всякие NAT'ы не протухали.

UFO just landed and posted this here
А что произойдёт, если во время передачи клиенту данных соединение разорвётся? Будет ли повтор, и сможет ли клиент обработать такой разрыв?
UFO just landed and posted this here
На том же DkLab'e в форуме есть другая интересная реализация, думаю это как раз то что принято называть comet: forum.dklab.ru/viewtopic.php?t=33589
«Идея основана на наличии скрытого
Ух! Спасибо за ссылку. Если оно не слишком сырое, то, конечно, вариант с nginx близок к идеальному.
P.S.
Вот ради таких комментариев и стоит публиковать велосипеды и выкладывать для них подробную документацию.
Всегда пожалуйста. :)
Дима, спасибо за идею
мы, пока идем первым путем,
перепишем все на Си, если получится — дам знать.
Дмитрий,

и все же я не до конца понял преимущества технологии Комет,
в первом случае, мы пуулим каждые 10 сек, да нагрузка на сервер есть, но если у нас сидит 20 000 пользователей, то эта нагрузка размывается на 2 000 запросов в сек. Запросы отдаются мгновенно, если использовать соответствующие технологии, напрмер мемкешед. Да, от трафика никуда не уйти, но трафик будет не такой уж и большой, по 128-512 байт на пустое сообщение. Не на много больше, чем во втором случае. Оплата трафика для провайдера, как правило по входящему трафику, или по соотношению, которое не должно превышать.

Во втором случае, я должен держать 20 000 соединений, но ОСь имеет конечный предел на кол-во одновременно подключенных соединений. Игорь Сысоев говорил, что ось можно подточить до 100 000 соединений, но реально это 20-30 К.
Only those users with full accounts are able to leave comments. Log in, please.