0,0
рейтинг
13 сентября 2009 в 02:58

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

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
Дмитрий Котеров @DmitryKoterov
карма
385,2
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (108)

  • +1
    APE
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        В продакшене нет, но планирую в скором будущем. Там ещё есть слабые места.
        • НЛО прилетело и опубликовало эту надпись здесь
          • +1
            Пока в продакшн не внедрили писать особо нечего — нет опыта применения. Как используем — напишу.
            • 0
              напишите — буду рад
            • 0
              Тоже с удовольствие почитаю…

              лишь бы не в духе: «99% процентов тем завершается словами, как сделаю отпишу» :)
          • 0
            о нем уже немного рассказывали — habrahabr.ru/blogs/webdev/60803/
    • –2
      Понятно понятно, то есть не использовали, но заклеймили велосипедистов? Или если есть APE, то всем остальным можно забыть о comet серверах?
      • +2
        Dklab_multiplexor не претендует на полную универсальность или исключительность (кстати, если знаете аналоги, близкие по простоте к multiplexor-у, пишите в комментариях).

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

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

                всё, выхожу из бессмысленного спора
                • НЛО прилетело и опубликовало эту надпись здесь
                • 0
                  Дети, не ссорьтесь. Я лично использую comet несколько лет *начал еще до того, как его этим словом обозвали). Всё работает, во всех браузерах. В зависимости от ситуации разными способами.
    • НЛО прилетело и опубликовало эту надпись здесь
  • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    По сути не хватает простенькой JS библиотечки для работы с сервером — чтобы само переподключалось и дергало обработчик по событию: ) Для совсем ленивых чтобы.
    • НЛО прилетело и опубликовало эту надпись здесь
      • –2
        Ну тут не вижу переподключения: ) Согласен — реализация много времени не займет.
        • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            Извиняюсь, это сильно!
      • 0
        Я правильно понимаю — это клиентская часть, подключаемая к искомому мультиплексору?
        • НЛО прилетело и опубликовало эту надпись здесь
    • +2
      Ага. На досуге выложу некоторый вариант.

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

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

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

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

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

      Что касается статистики, то ее можно смотреть в лог-файле сейчас. Если сделать tail -n1 /var/log/multiplexor, то вы как раз и получите такую статистику.
      • 0
        Понятно, а как насчёт групповых id-ов? Можно просто запятыми разделять…
  • 0
    erlang, flash sockets (+ js прослойка)
    • НЛО прилетело и опубликовало эту надпись здесь
  • +6
    Пару лет назад реализовывал подобный мультиплексор на Java. Благо там реализация синхронной очереди делается в пару десятков строк, достаточно эффективно и надежно. Несколько сотен запросов в секунду не создают тормозов.

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

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

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

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

        Я просто рассказывал про достаточно не очевидный момент с зомби-XHR, возможно это сэкономит кому-нибудь кучу времени.
    • НЛО прилетело и опубликовало эту надпись здесь
      • +1
        У меня было вообще забавно. Схема такая — страница при загрузке шлет серверу «я тут», а сервер регистрит её и начинает в ответ слать данные (у юзера машинка по карте начинает ездить). Все было зашибись пока не пришлось добавить один маленький инит-пакетик перед потоком данных. Выглядит всё здорово — сервер получает «я тут», высылает «инит», его видно в tcpdump, он проходит по логам XHR, но на страницу не попадает, сцуко!

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

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

        • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    А что произойдёт, если во время передачи клиенту данных соединение разорвётся? Будет ли повтор, и сможет ли клиент обработать такой разрыв?
  • 0
    Кстати для питонистов:

    www.olivepeak.com/blog/posts/read/simple-http-pubsub-server-with-twisted

    Как обычно профит в адаптации под себя.
  • –2
    Да, это же wave 0_о!
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    На том же DkLab'e в форуме есть другая интересная реализация, думаю это как раз то что принято называть comet: forum.dklab.ru/viewtopic.php?t=33589
    «Идея основана на наличии скрытого
  • +3
    Есть модуль для Nginx, реализующий эту функциональность: wiki.nginx.org/NginxHttpPushModule
    • +2
      Ух! Спасибо за ссылку. Если оно не слишком сырое, то, конечно, вариант с nginx близок к идеальному.
      P.S.
      Вот ради таких комментариев и стоит публиковать велосипеды и выкладывать для них подробную документацию.
      • 0
        Всегда пожалуйста. :)
  • 0
    Дима, спасибо за идею
    мы, пока идем первым путем,
    перепишем все на Си, если получится — дам знать.
  • 0
    Дмитрий,

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

    Во втором случае, я должен держать 20 000 соединений, но ОСь имеет конечный предел на кол-во одновременно подключенных соединений. Игорь Сысоев говорил, что ось можно подточить до 100 000 соединений, но реально это 20-30 К.

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