Pull to refresh

dklab_multiplexor: постоянное Javascript-соединение с сервером в условиях сотен тысяч онлайн-клиентов

High performance *
Dklab_multiplexor — это инструмент, который позволяет держать одновременно сотни тысяч долгоживущих открытых HTTP-соединений с сервером. Например, если на вашем сайте находится одновременно несколько сот тысяч посетителей, каждый из них может быть связан с сервером постоянным соединением, установленным из JavaScript. Это например, полезно при организации онлайн-чатов или мгновенных уведомлений.

Dklab_multiplexor не претендует на полную универсальность или исключительность (кстати, если знаете аналоги, близкие по простоте к multiplexor-у, пишите в комментариях). Это лишь простейший инструмент, который наконец-то дошли руки опубликовать.

Зачем это нужно?


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

Данную задачу можно решить двумя способами.
  1. Неправильный способ. Раз в 10 секунд делать из JavaScript запрос на сервер для проверки, не появилось ли новых сообщений. Этот метод не работает, если на сайте одновременно находится очень большое количество пользователей, т.к. нагрузка на сервер растет слишком быстро. Кроме того, потребление трафика пользователем также оказывается крайне высоким.
  2. Правильный способ. Устанавливать постоянное и длительное соединение с сервером, ожидая поступления данных через него. Если сообщений нет, соединение просто держится открытым на протяжение нескольких минут. Если соединение по каким-либо причинам закрылось, оно вновь открывается. В итоге и трафика потребляется мало, и нагрузка на сервер оказывается невелика. Так работает GMail, Мой Круг и т. д., и именно на этом принципе построен dklab_multiplexor.
+-------------------+                    ------------------ 
| Сервер обработки  |                   |                  |   <===WAIT=== Клиент A
| и базы данных     |  ======IN=======> |   Мультиплексор  |   <===WAIT=== Клиент B
| (e.g Apache + PHP |                   |                  |   <===WAIT=== Клиент C
+-------------------+                    ------------------ 
(указаны направления установления TCP-соединений).

Краткая инструкция по применению


Мультиплексор — событийно-ориентированный демон, написанный на Perl с применением библиотеки libevent. Рабочий расход памяти — порядка 10М на 1000 одновременных соединений. Начните с просмотра умолчательного файла конфигурации dklab_multiplexor.conf.

Запустим Мультиплексор

Запустите Мультиплексор и оставьте его работать:

# cd /path/to/dklab_multiplexor
# perl dklab_multiplexor.pl >/var/log/multiplexor.log 2>&1 &

Если Мультиплексор не запустился, скорее всего, в вашей системе отсутствует библиотеки libevent и Event::Lib. Установить их в RHEL-системе можно командами:

# yum install libevent-devel
# perl -MCPAN -e "install Event::Lib"

Прикинемся браузером клиента

Попробуем теперь проэмулировать браузер Клиента с идентификатором 1z2y3z. Запустите команду:

# wget -O- http://localhost:8088/?identifier=1z2y3z

Команда wget -O- открывает HTTP-соединение по указанному URL и распечатывает ответ сервера. Вы увидите, что wget как бы «подвис». Это нормально: «браузер» ждет, когда кто-то отправит в Мультиплексор блок данных для пользователя с идентификатором 1z2y3z. По умолчанию время ожидание WAIT_TIMEOUT равно 300 секундам. Если за это время ответ не приходит, соединение принудительно закрывается, и JavaScript-код Клиента, который вы напишете, должен установить новое соединение.

Итак, в реальной ситуации JavaScript-код Клиента устанавливает HTTP-соединение с Мультиплексором, используя XMLHttpRequest. При выполнении GET-запроса JavaScript указывает идентификатор пользователя, чтобы получать только сообщения для этого пользователя. Клиент ждет либо прихода данных о новых сообщениях от Мультиплексора (тогда он его отображает), либо же завершения соединения через 300 секунд. В обоих случаях Клиент сразу же устанавливает новое соединение с Мультиплексором и ждет от него нового ответа, и так до бесконечности. Таким образом, за счет медленных соединений поддерживается низкая загрузка сервера, а также обеспечивается мгновенность передачи нового сообщения от Сервера к Клиенту.

Передадим Мультиплексору данные для Клиента

Откройте вторую консоль на сервере, где у вас «висит» только что запущенный wget. Давайте передадим Мультиплексору на порт 10010 (см. IN_ADDR) строчку «Hello!» и укажем, что она предназначена для клиента с идентификатором 1z2y3z. Наберите в консоли команду:

# telnet localhost 10010
HTTP/1.1 200 OK
X-Multiplexor: identifier=1z2y3z

Hello!

После этого нажмите Ctrl+], потом q и Enter, чтобы окончить передачу данных. Постарайтесь уложиться в 20 секунд (см. IN_TIMEOUT), т.к. иначе Мультиплексор сам закроет соединение, не дождавшись данных.

Мультиплексор реализует буферизацию данных. Таким образом, если на момент передачи сообщения некоторый Клиент не был подключен к Мультиплексору (например, он как раз переходит на другую страницу сайта), Мультиплексор сохранит сообщение (максимум на 100 секунд, см. OFFLINE_TIMEOUT) и передаст его Клиенту, как только он подключится.

Фактически, мы сейчас «руками» проэмулировали то, что должен делать скрипт на сайте при приходе нового сообщения для пользователя 1z2y3z. Соответствующий PHP-код может выглядеть так:

$f = fsockopen("localhost", "10010");
fwrite($f, 
  "HTTP/1.1 200 OK\n" .
  "X-Multiplexor: identifier=1z2y3z\n" .
  "\n" .
  "Hello!\n"
);
fclose($f);

Вместо X-Multiplexor можно использовать любой другой заголовок. Мультиплексор ищет строчку identifier=* в любом месте передаваемых данных.

Ура, заработало!

Если вы все сделали правильно, то wget -O- в соседней консоли «отвис», а на экране появилась строчка «Hello!». Можно видеть, что Клиенту пришли в точности те данные, которые были отправлены Мультиплексору, «байт в байт». С точным протоколом передачи информации между сервером и JavaScript-частью вы должны определиться сами при разработки скриптов вашего сайта.

Скачать утилиту и почитать технические подробности можно тут: dklab.ru/lib/dklab_multiplexor
Tags:
Hubs:
Total votes 103: ↑97 and ↓6 +91
Views 6.3K
Comments Comments 108