Пользователь
0,0
рейтинг
18 декабря 2011 в 20:58

Разработка → Исследование производительности сервера SockJS

Доброе время суток!

Так уж сложилось, что я занимаюсь всякими разнообразными push технологиями с использованием Tornado. Чуть ранее описывал Tornadio2, серверную реализацию протокола socket.io поверх Tornado.

Теперь хочу представить похожий проект — sockjs-tornado.

Для тех кому не очень интересно, есть другая полезная информация: сравнительное нагрузочное тестирование PyPy 1.7 против CPython 2.6.6, sockjs-node и socket.io (оба на node.js 0.6.5). Все под катом :-)

Во первых, что такое SockJS? Это клиентская библиотека написанная на javascript, которая имитирует API Websocket'ов, но при этом поддерживает все браузеры путем использования различных суррогатных заменителей в виде ajax long-polling, jsonp-polling и тому подобных. В целом, весьма похожа на socket.io, но с некоторыми ключевыми отличиями.

Небольшое отступление — я не имею никакого отношения к клиентской части библиотеки, разве что отсылал баг-репорты и всячески досаждал ее разработчикам.

Так зачем оно надо, если есть socket.io?
Приведу пару причин, которые привели к разработке SockJS:
1. Разработчики socket.io, начиная с версии 0.7, пошли куда-то не туда. Вместо того, что бы исправлять ошибки, добавлять поддержку для разных браузеров, они решили сделать API более высокоуровневым. Я не спорю — все новшества очень удобные, но количество ошибок не уменьшилось. Например достаточно серьезный race condition не могут закрыть больше 3х месяцев. Подключение после отключения не работает до сих пор. Ну и тому подобное.
2. Иногда не хочется привязываться к конкретной библиотеке. Если использовать socket.io, то отказаться от нее будет уже сложно, так как придется менять все места где есть привязка к socket.io.

Так что такое SockJS?
1. Как уже было замечено ранее, это простая замена Websocket API для браузера. Соответственно, переезд существующего приложения использующего вебсокеты будет достаточно безболезненным (если не говорить о серверной части)
2. SockJS работает даже в Opera, которую socket.io ну очень не любит. Кроме того, SockJS правильно работает с разными антивирусами — откатывается на другой транспорт, тогда как socket.io вообще не может установить соединение.
3. SockJS поддерживает streaming протоколы: одно постоянное соединение от сервера, для исходящих данных. socket.io отказался от streaming транспорта начиная от версии 0.7.
4. Протокол сильно проще и очень хорошо документирован. Для разработчиков даже есть набор тестов, которые должна проходить серверная реализация.
5. Масштабируемость заложена в протокол. Например, load balancer'у не надо работать с куками, что бы организовать sticky session — вся необходимая информация уже есть в URL.
6. Библиотека очень хорошо протестирована в разных условиях, в наличие даже есть qunit тесты, которые проверяют и клиент и сервер прямо из браузера. Например вот пример тестов для sockjs-node: http://sockjs.popcnt.org/

В целом, эта штука просто работает.

Теперь ко второй части статьи, производительности.

После написания sockjs-tornado, решил проверить как он в сравнении с «родным» сервером написанном на node.js. Сейчас node.js весьма модный, особенно часто говорят о его производительности в различных push технологиях. Заранее скажу — результаты тестирования меня весьма удивили.

Методология тестирования была выбрана очень простая: у нас есть чат сервер с одной комнатой. Каждое входящее сообщение сервер просто отправляет всем участникам чата. Если интересно, вот код сервера.

Есть Websocket клиент, который посылает ping и ждет «свой» ответ. После получения ответа, считает время затраченное между отсылкой и приемом. Результаты для разных уровней параллелизма и количества отправленных сообщений сохраняются и по ним строится график.

Возможно некоторые будут спрашивать — а что собственно тестируется? А тестируется вот что:
— Скорость реализации Websocket протокола для разных серверов
— Максимальное количество сообщений, при котором сервер начинает захлебываться
— Накладные расходы на поддержку большого количества соединений
— Время отклика при разных уровнях нагрузки

На другой вопрос, а зачем нам нужен «тупой» чат, который вообще без логики? Если кто сталкивался с таким проектом как Humble Indie Bundle, у них количество заработанных денег показывается в реальном времени. Так вот, они используют «брокер», который «держит» большое количество веб клиентов. А так же у них есть источник данных (producer), который время от времени посылает брокеру сколько денег было заработано. Брокер должен разослать эту информацию всем своим подключенным клиентам. Чем быстрее работает брокер, тем большее количество клиентов он сможет обслужить за минимальное время.

Исследование делалось на английском, так как разработчики sockjs просили сделать сравнительное тестирование с sockjs-node и его можно посмотреть прямо тут. Если кого заинтересует, могу перевести статью на русский.

Если вкратце, то получается следующая картина:
— sockjs-node может отправлять до 45,000 сообщений в секунду при среднем времени отклика в 200 мс.
— sockjs-tornado на cpython 2.6.6 может выдавать до 55,000 сообщений в секунду при времени отклика в 200 мс
— sockjs-tornado на pypy 1.7 просто «разрывает» со своими 150,000+ сообщениями в секунду.

Конечно, сервера могут отправлять и большее количество сообщений в секунду, но время отклика растет и приложение перестает быть realtime :-)

Сравнительный график можно посмотреть тут. По оси X у нас количество отправленных сервером сообщений за одну секунду. По оси Y — время отклика. Каждая линия это комбинация сервера (node = sockjs-node, socket.io = socket.io node, cpython = sockjs-tornado на cpython, pypy = sockjs-tornado на pypy 1.7) с количеством одновременных подключений. socket.io приведен для примера производительности другого проекта на node.js.

Даже если не сравнивать node.js и cpython, производительность pypy оказалась для меня полной неожиданностью.

Ну и в заключение.

Рекомендую посмотреть в сторону SockJS если планируется какая либо функциональность реального времени, даже если уже рассматривали варианты с socket.io. И надеюсь что sockjs-tornado кому-то еще пригодится.
Сергей @Joes
карма
52,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

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

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

  • 0
    А как на счет загрузки CPU и потреблени памяти на сервере?
    • +1
      Прошел по ссылке, про ОЗУ прочитал.
      на 2к клиентов:
      sockjs-node around 36 MB
      sockjs-tornado on CPython around 52 MB
      sockjs-tornado on PyPy around 100 MB.

      Я думал nodejs ест больше
    • +3
      Когда начало «тормозить» — 100%, т.е. одно ядро целиком. А память есть в исследовании, PyPy при 2000 клиентах скушал около 100 мб, тогда как CPython около 55 мб.
  • +3
    Как раз на днях читал оригинал, не сказал бы что удивлен, на PyPy возлагаем надежды, а то что он памяти кушает больше, это не беда. Как раз начал писать проект при помощи tornadio2, и был очень приятно удивлен, моё первое знакомство с торнадо было более года назад, и тогда не сказал бы что было очень удобно писать логику приложения, а вот tornado + socket.io (т.е tornadio2) просто очень удобно описывать взаимодействие через события (делать вызовы при помощи emit). Да конечно не без проблем, но по ходу дела будем решать, да с оперой не ахти, последний апдейт хрома поломал что то с сокетами (тут надо смотреть скорее что в торнадо), но я рад что за последний год ws начал продвижение, это на самом деле очень удобно.
    • +1
      Я думаю написать простую библиотеку которая даст функционал аналогичный socket.io поверх обычных вебсокетов (или sockjs). Там нет ничего сложного.

      Что до поддержки разных браузеров — увы, sockjs тут лучше. Хотя бы потому, что автоматически тестируется при сборке релиза в куче браузеров с помощью http://testling.com.

      TornadIO2 забрасывать не собираюсь — баги будут исправляться, но нового функционала точно не будет.
      • 0
        хм, что то не сразу понял после прочтения, подумал что SockJS лишь имитирует WS. Что ж, обязательно попробую, при том что как мне кажется переход должен быть прозрачным, хотя для себя не вижу проблем в socket.io, но это пока что, нужно углубиться в эту тему. Спасибо за труд.

        P.S testling насколько я понял не тестируется на мобильных браузерах?
        • 0
          SockJS имитирует только WS. Соответственно передаются только строки.

          Я хочу написать библиотеку, которая даст функционал аналогичный emit() в socket.io, но без использования socket.io. Например, можно будет взять «сырой» торнадо и по вебсокетам делать emit(). Как-то так.

          Testling — не тестируется, но я проверял — работает во всех «главных» браузерах.
          • 0
            а у меня в opere подтормарживает… в остальных гуд…
      • +1
        джу библиотеку, серьезно
  • +2
    Узнал из статьи о SocksJS, и очень этому рад
  • 0
    Эх, хорош он, еще был бы написан нормально (я про клиентскую часть на кофескрипте)
    • +1
      Это серверная на кофескрипте, клиентская на чистом js: https://github.com/sockjs/sockjs-client/tree/master/lib. coffeescript используется только для минификации и сборки общего файла.
  • 0
    Жаль что про sockjs только сейчас узнал, добрая часть когда уже написана под Socket.io =(

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