Пользователь
0,0
рейтинг
12 декабря 2012 в 11:35

Разработка → Вебсокеты: боевое применение

imageВебсокеты — это прогрессивный стандарт полнодуплексной (двусторонней) связи с сервером по TCP-соединению, совместимый с HTTP. Он позволяет организовывать живой обмен сообщениями между браузером и веб-сервером в реальном времени, причем совершенно иным способом, нежели привычная схема «запрос URL — ответ». Когда два года назад я присматривался к этому стандарту, он был еще в зачаточном состоянии. Существовал лишь неутвержденный набросок черновика и экспериментальная поддержка некоторыми браузерами и веб-серверами, причем в Файрфоксе он был по умолчанию отключен из-за проблем с безопасностью. Однако теперь ситуация изменилась. Стандарт приобрел несколько ревизий (в том числе без обратной совместимости), получил статус RFC (6455) и избавился от детских болезней. Во всех современных браузерах, включая IE10, заявлена поддержка одной из версий протокола, и есть вполне готовые к промышленному использованию веб-серверы.

Я решил, что настало время попробовать это на живом проекте. И теперь делюсь, что из этого вышло.

Суть задачи


На моем личном небольшом сайте Клавогонки.ру есть центральная часть — список действующих в данных момент игр-заездов. Список крайне динамичный: новый заезд создается игроками каждые несколько секунд, иногда несколько в секунду. Заезды начинаются с отсчета времени, по завершению перемещаются из раздела открытых игр в раздел активных. После выхода всех игроков заезд убирается со страницы. В один заезд заходит от одного и иногда до ста игроков, что требуется отображать тут же.

image

Как это работало раньше


Изначально, когда появилась необходимость сделать эту часть функциональности сайта, возникло много трудностей с динамическим обновлением списка. На странице списка могут находиться десятки человек одновременно, каждый из которых хочет видеть свежую картину. У многих заездов может быть таймаут отсчета от создания до старта всего 10-20 секунд, и чтобы успеть присоединиться к ним, обновление должно происходить достаточно живо.

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

Самым очевидным и простым решением здесь на первый взгляд казался long-polling — висящее подключение к серверу, которое обрывается в момент поступления нового события и переоткрывается заново. Однако после некоторых тестов этот вариант тоже оказался нежизнеспособным: события поступали непрерывным потоком, ведь клиенту нужно сообщать не только о создании новой игры, но и об изменении параметров всех игр (например, старт таймаута, смена статуса, состава игроков), и количество запросов начало вызывать определенную степень недовольства у сервера. Да и оверхед на открытие-закрытие запросов тоже выходил немаленький.

HTTP-streaming не получилось использовать из-за проблем с прокси-серверами у многих пользователей.

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

Система показала себя неплохо и проработала долгое время. Однако был большой минус — очень трудно зайти в заезд с 10-секундным таймаутом до старта. Кроме того, это совсем не соответствовало духу динамичной гоночной онлайн-игры и выглядело не слишком технологично в целом.

Увидеть эту страницу в ее старом варианте вы можете по этой ссылке.

Как это работает сейчас


Если говорить кратко, вебсокеты позволили внести драйв в весь этот процесс.

Для начала был выбран сервер, который должен жить в связке с действующим игровым бэкэндом. По ряду причин я выбрал для этого node.js — событийно-ориентированная модель и хорошо развитые коллбэки в javascript идеально подошли для этой задачи.

Общей средой общения между php-бэкэндом и сервером на node.js стали pubsub-каналы redis. При создании новой игры или любом действии, изменяющем данные, php делает примерно следующее (код здесь и далее сильно упрощен):

$redis = new Redis();
$redis->pconnect('localhost', 6379);
$redis->publish("gamelist", json_encode(array(
		   		"game created", array(
		   			'gameId' => $id))));

Redis работает как отдельный демон на отдельном TCP-порте и принимает/рассылает сообщения от любого количества подключенных клиентов. Это дает возможность хорошо масштабировать систему, невзирая на количество процессов (ну и серверов, если думать оптимистично) php и node.js. Сейчас крутится примерно 50 php-процессов и 2 node.js-процесса.

На стороне node.js при старте идет подключение к прослушке redis-канала под названием gamelist:

var redis = require('redis').createClient(6379, 'localhost'),
redis.subscribe('gamelist');	

Для работы с клиентами используется обвязочная библиотека Socket.IO (upd: товарищи Voenniy и Joes в комментах говорят, что есть более качественные альтернативы вроде SockJS и Beseda, что вполне может быть правдой). Она позволяет использовать вебсокеты как основной транспорт, откатываясь при этом на другие транспорты вроде флеша или xhr-polling если браузер не поддерживает вебсокеты. Вдобавок, она упрощает работу с клиентами в целом, например дает API для мультиплексирования и разделения подключенных клиентов по разным псевдокаталогам (каналам), позволяет именовать события и некоторые другие плюшки.

var io = require('socket.io').listen(80);
var gamelistSockets = io.of('/gamelist');	

При подключении браузера клиента к ws://ws.klavogonki.ru/gamelist он распознается как подключенный к socketio-каналу gamelist. Браузер для этого делает следующее:

<script src="http://ws.klavogonki.ru/socket.io/socket.io.js" type="text/javascript"></script>
...
<script type="text/javascript">
var socket = io.connect('ws.klavogonki.ru/gamelist');
</script>


При поступлении по redis-каналу события из бэкэнда оно всячески предварительно анализируется и потом отсылается всем подключенным клиентам в gamelistSockets:

redis.on('message', function(channel, rawMsgData) {		
		
	if(channel == 'gamelist') {	
			
		var msgData = JSON.parse(rawMsgData);		
		var msgName = msgData[0];		
		var msgArgs = msgData[1];  
			
		switch(msgName) {
			
			case 'game created': {
				...
				gamelistSockets.emit('game created', info);	
				break;
			}		
				
			case 'game updated': {
				...
				gamelistSockets.emit('game updated', info);					
				break;
			}
				
			case 'player updated': {
				...
				gamelistSockets.emit('player updated', info);					
				break;
			}
		}			
	}			
});

Браузер получает событие ровно таким же образом и рендерит необходимые изменения на странице.

socket.on('game created', function(data) {
	insertGame(data);		
});
				
socket.on('game updated', function(data) {
	updateGame(data);	
});
		
socket.on('player updated', function(data) {
	updatePlayer(data);			
});


Принцип совершенно прост и ясен. Продвинутые технологии в основе этой схемы позволяют сильно упростить процесс и сосредоточиться на логике самой работы. Хотя пришлось несколько повозиться с переделкой некоторых частей php-кода для работы в идеологии «сообщаем об изменении, а не о состоянии», а также вынести домен вебсокетов на отдельную от основной машину (чтобы не мучиться с разделяющим прокси на 80 порту), но в сухом остатке плюсы вышли очень существенными:

  • Высочайшая динамичность интерфейса, обновление происходит в реальном времени, можно отслеживать единичные изменения и чувствовать себя в онлайн-игре, а не на страничке чата 90-х годов.
  • Практически полное отсутствие необходимости в кэшировании, ведь данные идут транзитом от бэкэнда прямо в браузер.
  • Органичная экономия трафика на отсылке только необходимых изменений состояния (если постараться прикрутить компрессию, то будет еще интересней).
  • Роста сетевой нагрузки практически незаметно, так как node.js разрабатывался как раз с целью держать и обрабатывать любое мыслимое число одновременных подключений; а рост нагрузки на цпу даже упал, ведь просчет изменения состояния делается один раз на бэкэнде и всем клиентам рассылается уже в готовом виде.
  • Событийно-ориентированная схема дает возможность знать о всех моментах изменений данных и, например, делать анимация всплывания и уплывания при этом.

Сплошной профит, короче.

Посмотреть на то, что получилось в итоге, вы можете здесь. Разница видна невооруженным взглядом.

В качестве бонуса две таблички, небольшая статистика по аудитории Клавогонок, браузеры и используемые в Socket.IO транспорты:
Браузер Доля Транспорт Доля
Chrome 51% websocket 90%
Firefox 20% xhr-polling 5%
Opera 15% flashsocket 4%
IE (примерно пополам 8 и 9) 6% jsonppolling 1%
Как видно, вполне готово к употреблению.

Итог


Тут могла бы быть заключительная резюмирующая часть с итогами, библиографией и моралью. Но я сэкономлю ваше время и скажу просто: вебсокеты — это очень круто!

P.S. Во вновь разрабатываемых частях проекта (включая описанное выше) используются также такие интересные слова, как mongodb и angular.js. Если есть интерес, то следующие топики будут на эту тему.
Артём @artch
карма
161,3
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

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

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

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

  • –14
    > Продвинутые технологии в основе этой схемы позволяют сильно упростить процесс и сосредоточиться на логике самой работы.

    У меня только один вопрос. Почему нагромождение технологий друг на друга называется «упростить процесс»?

    • +11
      Это вы называете нагромождением технологий? Это совершенно минимальный джентльменский набор риалтаймового проекта. Попробуйте решить эту задачу меньшим количеством. Вы бы знали, что во всяких фейсбуках происходит, вот где нагромождение.

      А упрощение это потому, что непосредственно кода стало в несколько раз меньше, а работает всё эффективнее и производительнее.
      • +7
        > Это вы называете нагромождением технологий?

        Итак. У вас уже есть сайт на РНР. Вам нужно решить какую-то задачу. Вы почему-то взять node.js (хотя работа с вебсокетами в PHP более, чем возможна). ВНЕЗАПНО оказалось, что надо еще каким-то образом общаться между node.js и PHP. Правильно, давайте навернем еще сверху pubsub через редис.

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

        > Это совершенно минимальный джентльменский набор риалтаймового проекта.

        Hype Driven Development во всей красе.
        • +9
          Технологии удобного событийно-ориентированного программирования на php — в студию, пожалуйста. А также было бы интересно услышать о том, как можно общаться между различными php-процессами (отправляющими и принимающими сообщения) без какой-либо общей среды вроде redis.
          • –4
            > Технологии удобного событийно-ориентированного программирования на php — в студию, пожалуйста.

            Прекращайте вестись на hype. Даже в рамках веб-сокетов это банальные запрос-ответ или стейт-машины.

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

            А зачем их разделять?
            • +10
              Вы ругаете hype, а сами тоже себя ведете не лучшим образом. Это даже критикой назвать нельзя — это троллинг.

              С давних пор Erlang ассоциируется у меня (и, кстати, не только у меня) лично с вами. Недавно в неформальной беседе мы с одним очень хорошим моим товарищем просто пустились в рассуждения различных технологий без пены у рта. И когда затронули Erlang, факторами в пользу того, чтобы не использовать его с моей стороны были: экономический (специалисты стоят дорого) и субъективный (функциональная парадигма, которая после всепроникновения ООП для многих непонятна). А знаете, что я услышал в ответ? Мой знакомый сказал: «а еще его пиарят какие-то отморозки… Мамут вообще неадекватный — ничего спросить нельзя, набрасывается сразу» (цитата сильно неточная — в прошлый раз за мат меня отправили в ридонли).

              Вы олицетворяете Erlang для масс, а ведете себя очень странно. Вам не плевать, чем пользуется конкретно этот товарищ?
              • +2
                > Это даже критикой назвать нельзя — это троллинг.

                Покажите, в каком месте я троллю. Вы действительно считаете нагромождение технологий друг на друга упрощением?

                > а еще его пиарят какие-то отморозки… Мамут вообще неадекватный — ничего спросить нельзя, набрасывается сразу

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

                Более того, в последних двух топиках (один из которых этот) про Erlang я вообще не начинаю говорить. Что опять же характеризует не меня, а людей, неспособных понять те простейшие вещи, что я пишу.

                На все вопросы я четко и конкретно отвечал. Хотя, если ваш друг — школьник типа тут: habrahabr.ru/post/160447/#comment_5505135 то мне жаль вашего друга (подробнее: habrahabr.ru/post/160447/#comment_5514995)

                > Вы олицетворяете Erlang для масс, а ведете себя очень странно. Вам не плевать, чем пользуется конкретно этот товарищ?

                Мне плевать. И вопрос я задал совершенно конкретный: Почему нагромождение технологий друг на друга называется «упростить процесс»?

                Где вы здесь видите хоть слово про Erlang?

                P.S. На остальные вопросы в этом топике, увы, отвечать не буду, потому что школота, неспособная понять простейший текст, успела снова слить мне карму.
                • +2
                  P.S. На остальные вопросы в этом топике, увы, отвечать не буду, потому что школота, неспособная понять простейший текст, успела снова слить мне карму.

                  Грамотный вы наш дружище, прежде чем так откровенно сливаться, ответьте простейшим текстом хотя бы на этот простейший вопрос: как можно не разделять процессы в php, имея необходимость поддерживать постоянное соединение с клиентами по вебсокету и отвечать на традиционные http-запросы? И как можно без чего-то вроде redis общаться между ними, если процессы работают на разных машинах (мы же ведь грамотные и думаем про масштабирование)?

                  На вопрос, какого черта это всё надо писать на php, когда есть гораздо более удобные ЯП, ответа даже уже и не прошу.
                • +1
                  Дмитрий, я не считаю, что нагромождение технологий — это упрощение. И более того — я поддерживаю основную канву ваших рассуждений. Но, опять же, назвать совершенно незнакомого человека школотой — это тоже очень характеризует ваше настроение. И, кстати, его незачем жалеть, с ним вообще все как надо — человек юзает питон и плюсы (когда оно требуется), и смотрит на все эти перепалки с выражением дикой усталости и каплей иронии.

                  > Hype Driven Development во всей красе
                  Вот, например. Это я и считаю троллингом.

                  > Хотя, если ваш друг — школьник… то мне жаль вашего друга
                  И это… это не информативно.

                  > Где вы здесь видите хоть слово про Erlang?
                  Нигде. А почему вы спросили?

                  Если бы вы были чуточку добрее к людям, вы привлекли бы на свою сторону гораздо большее количество людей. Потому, что мы — люди — не мухи. Нам не плевать, на что слетаться.
                  • 0
                    Дмитрий, я не считаю, что нагромождение технологий — это упрощение.

                    Тут дело в том, что иногда задействование какой-то иной технологии, нежели использование той, к которой привыкли, может резко сократить количество необходимого кода для решения конкретной задачи. Собственно, технологии для этого и создаются. Примерно это я имел в виду в топике под «упрощением».
                    • +1
                      Давным давно известный факт: чем больше в агрегате узлов и частей, тем выше вероятность поломки. К php + nginx + mysql вы добавили еще redis + node.js — это повышает риск возникновения сбоя в каком-либо из узлов. Даже если в каком-то месте вместо 100 строчек кода вы напишете 10 — это будет не аргументом.

                      Здесь явное противоречие. Если мыслить глобально, в рамках всей вашей системы, то вы идете неверным путем (выше описал). А если мыслить локально, то да — вы успешно решили проблему. Вы сделали то, что было надо, все работает.
                      • +1
                        Подождите, вы тоже, что ли, будете утверждать, что без redis здесь можно обойтись? Вообще, если говорить о практике, то redis на сервере работал задолго до этой задачи для других целей. Но даже и без этого тут его определенно пришлось бы ввести. Это раз.

                        А вот два: демон на php является другой технологией, другим звеном по отношению к cgi на php. Он будет работать как совершенно отдельное звено, и неважно, какой именно интерпретатор запускается внутри /etc/init.d/websocket-server. При этом js как язык существенно удобнее php в данном круге задач.

                        Поэтому получаем: «node.js+redis+php-cgi» vs «php-daemon+redis+php-cgi». Где я неправ?
                        • 0
                          Нет… я бы в данном случае (хотя я использую PHP уже давно и продолжу использовать его в обозримом будущем — в других местах) не использовал бы, скорее, PHP. А все демоны на PHP — это те еще демоны… в плохом смысле, разумеется.
                          • 0
                            С тезисом про упрощение в данном случае теперь, надеюсь, согласны?

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

                            А кодирование упрощается выбором правильных инструментов для этого. И выбор этих инструментов осуществляется с нуля, так как задача тоже поставлена с нуля.
                            • 0
                              Иногда то, что кажется решением задачи решением не является. А является решением какого-то из следствий задачи, понимаете?

                              «Ни одну проблему нельзя решить на том уровне сознания, на котором она была создана» (с) Альберт Эйнштейн

                              Поэтому здесь спор уже, хоть и конструктивный (если бы задача была поставлена именно так, я решил бы, может быть, ее именно так — так быстрее), но это уже не война технологий, а война взглядов. Я же написал: с локальной точки зрения задача решена. Проблема в том, что многие мыслят глобально, а значит считают, что задача была ложная. Оттого и решение кажется им неверным.
                              • 0
                                Вероятно, в данном случае «они» предлагают написать собственный pubsub-демон на сях, который будет висеть на TCP-порте и будет рассылать туда-сюда сообщения из php? А потом допишут к этому сервису текстовый протокол передачи для удобства и выложат в мир под названием… ну скажем, myRedis.

                                Это, знаете, похоже на такого анекдотичного программиста, до старости доводящего до совершенства код одной-единственной функции.
                        • +3
                          Кстати, мне кажется, я понял, что имелось в виду под «а зачем разделять php процессы». Ах, Дмитрий… ах, он такой… это он так тонко подтравливает php. Дмитрий привык, что Erlang умеет «расползаться» по ядрам процессора внутри себя самого, не плодя процессы… и его сложно обвинять в том, что он считает это правильным и красивым решением.

                          Только не вздумайте писать, что не будете изучать Erlang потому, что он слишком… специфичный — сразу попадете в разряд «школота» и «слабаки» )))
                          • 0
                            У меня на отдельном сервере работает ejabberd — чат для Клавогонок. На эрланге. Хорошая штука, я вдоволь в нем поковырялся.

                            Я знаю о богатых возможностях создания процессов в эрланге. Однако возможность расползаться по памяти нескольких машин мне неизвестна. Поэтому какая-то общая среда, всё же, нужна в любом случае. Даже если она есть своя собственная в эрланге, в php её нет.
                        • 0
                          Можно обойтись. Возможно Redis не лучший выбор для реализации обмена сообщениями, а, скажем, Gearman бы больше подошёл. Но вы решили на нагромождать технологии :)
                          • 0
                            Обойтись без чего-то вроде redis вообще, а не без конкретного redis в частности.
                        • 0
                          > Подождите, вы тоже, что ли, будете утверждать, что без redis здесь можно обойтись?

                          Можно ли обойтись без redis для pubsub? Вот скажите, почему ни одной из *MQ решений не подошло для pubsub между процессами? Начиная с ZMQ, которому даже отдельный демон не обязателен?

                          Я понимаю, что там есть pubsub, но redis — key/value в первую очередь. В заточенных на MQ решениях всё намного круче и гибче.
                          • 0
                            Не-не, вы не поняли контекст этого треда комментов. Конечно же имеется в виду не сам Redis как таковой, а отдельно стоящий pubsub-сервис. dmitriid предлагает обойтись вообще без оного. Не представляю, как.
                            • 0
                              Вы тоже начинаете перегибать… ничего такого он не предлагал
                              • 0
                                тыц:
                                ВНЕЗАПНО оказалось, что надо еще каким-то образом общаться между node.js и PHP. Правильно, давайте навернем еще сверху pubsub через редис.

                                Так как от дальнейшей дискуссии товарищ ушел, то я интерпретирую его слова самостоятельно: если бы не было node.js, то и redis как pubsub-сервис бы не понадобился. Вопрос, какое отношение имеет выбор интерпретатора демона к необходимости завести общую среду передачи сообщений, остается невыясненным.
                                • 0
                                  Если вернуться к гипотезе о том, что критика была про редис, а не про сам pubsub в качестве IPC. Редис, а не что-то другое, необходимость? Что ещё делает редис?
                                  • 0
                                    Критика была о том, что вообще нужен pubsub, так как-де «надо еще каким-то образом общаться» между двумя разными платформами. Как будто «каким-то образом общаться» не придется, если вторая платформа будет не на js, а на php.

                                    Редис в данной задаче нужен только для pubsub, больше ни для чего. А в целом пригодится и как кэш, естественно.

                                    Писать свой pubsub просьба не предлагать :)
                              • +2
                                Ну как же:
                                Итак. У вас уже есть сайт на РНР. Вам нужно решить какую-то задачу. Вы почему-то взять node.js (хотя работа с вебсокетами в PHP более, чем возможна). ВНЕЗАПНО оказалось, что надо еще каким-то образом общаться между node.js и PHP. Правильно, давайте навернем еще сверху pubsub через редис.

                                По-моему вполне недвусмысленное предложение избавиться от node.js и redis. Демона для веб-сокетов написать тоже на PHP и средствами PHP же реализовать обмен сообщениями между CGI-частью и демоном. Возможно? Возможно. Имеет ли смысл без самоцели избежать «нагромождения технологий»? Ни одного аргумента за это, просто голословное утверждение. Причём почему-то лояльность к nginx, а ведь асинхронный событийный веб-сервер тоже на PHP можно написать. И базу данных или другое хранилище. И никакого нагромождения технологий — ОС и один процесс PHP в памяти. Ну или несколько процессов/потоков если выбрать другую модель.
                        • +1
                          Вместо редиски вполне можно слать данные в сокет, а в ноде слушать его. Итого — минус редиска.
                          • +1
                            Плюс своя реализация сообщений в ноде (хотя может она там есть, но по контексту -нет)
                          • 0
                        • 0
                          Насчет pubsub без редиса — переносите очередь сообщений в NodeJS и всё.
                          Делаете в Node внутренний URL /post_message и из PHP обращаетесь туда HTTP клиентом с теми же данными, какие пихали в редис.
                          Чем такой подход не устраивает?
                          • 0
                            Вроде в редис обращаются из пхп-апи…
                          • +1
                            Нод может быть запущено много, и они могут быть на разных машинах. При этом разные клиенты подключаются к разным нодам через балансировщик, но получать должны одни и те же сообщения от бэкэнда.
                      • +1
                        Свой код зачастую оказывается самой ненадежной частью программного комплекса. Особенно если код низкоуровневый, системный, а ты в этой области обладаешь в лучшем случае лишь общими теоретическими знаниями. Ладно если стоит альтернатива свой код или код другого одиночки. Но вот что 100 строк своего кода более надежны чем даже миллион строк кода продукта с большой историей, крупным сообществом, финансируемого крупной компании далеко далеко не факт.

                        Так что 10 своих строк и качественный продукт на миллион строк, как минимум, аргумент, который нужно рассмотреть против 100 своих строк, даже с точки зрения надежности. А надежность не единственный фактор для выбора. В пользу 10 строк говорят ещё такие факторы как скорость разработки и простота поддержки.
                        • 0
                          Так… и что же?
                          • 0
                            Утверждение «10 строк не аргумент» как минимум спорно даже с точки зрения надежности. А надежность не единственный критерий выбора способа решения задачи.
                  • +3
                    Отвечу только один раз.

                    > > Hype Driven Development во всей красе
                    > Вот, например. Это я и считаю троллингом.

                    Давайте восстановим контекст:

                    "
                    > Это (php + redis + node.js?) совершенно минимальный джентльменский набор риалтаймового проекта.
                    Hype Driven Development во всей красе.
                    "

                    Это не троллинг, а называние вещей своими именами.

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

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

                    Хотя нет, пусть они будут на другой стороне.

                    PS.

                    В частности, в комментариях было объяснено, что автор топика планирует перейти с php на node.js полностью (что уберет кусок нагромождений). Если бы это было сказано сразу, я бы слова не сказал. Возможно, у меня были бы другие возражения, но вряд ли (обычно у меня возражения только по обилию слюней в описании крутости node.js)

                    А в топике общее описание идет в стиле «вот у нас есть куча разрозненного всего, мы это свяжем вместе костылями из говна и палок» с неожиданным выводом «это удобно и все упрощает!». Будет смешно, если там рядом еще где-то валяется MySQL/Postgres для данных, а редис прикручен только ради pubsub'а.
                    • 0
                      А в топике общее описание идет в стиле «вот у нас есть куча разрозненного всего, мы это свяжем вместе костылями из говна и палок» с неожиданным выводом «это удобно и все упрощает!».

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

                      В самом голом посте, без учета единого моего коммента, речь идет о сугубо минимальном наборе технологий, которые необходимы в данном конкретном случае. Если бы вы начали читать этот пост в чуть более лучшем настроении и без какой-то странной изначальной предустановки, вы бы поняли это.

                      И вы до сих пор не оказались способны доказать мне, что это можно решить более просто в технологическом плане.
                    • +1
                      > Если люди неспособны понять простейшие вещи и обижаются, когда вещи называют своими именами, то, извините, не нужно мне таких людей ни на чьей стороне.
                      Если бы люди были способны самостоятельно правильно понять простейшие вещи, ваши комментарии не потребовались бы. Возможно, и этого топика не было бы.

                      Я же говорю, у меня лично претензий нет, я просто отметил, что не все могут здраво относиться к такой манере. Я по себе это знаю… и стараюсь быть добрее ))
                • +2
                  Вы действительно считаете нагромождение технологий друг на друга упрощением?

                  Если они не дублируются и используются по назначению, то да. Как правило они предоставляют высокоуровневые интерфейсы к реализации нужных для проекта функций. Выбор состоит лишь в том, что использовать: специализированный инструмент, универсальный инструмент с какой-то обвязкой или полностью свою реализацию. Вот стоит задача обмена сообщениями между двумя процессами, пускай даже написанных на одном языке, но возможно исполняющихся на разных машинах. Можно взять Redis, в котором эта функция реализована «из коробки», имеет привязки ко множеству языков, имеет крупное сообщество, финансируется и курируется известной компанией, для которой наличие эффективного способа обмениваться сообщениями между процессами на разных хостах (пускай и виртуальных) большой плюс в их основном бизнесе. Можно взять MySQL и использовать его для хранения сообщений, написав обвязку для работы с ними. Можно написать полностью свое решение на любимом языке, используя только низкоуровневые средства ОС вроде сокетов или файлов. Какой способ будет проще? Какой способ будет проще? Тот, где абстракция сообщения уже реализована, тот, где реализована абстракция записи, вокруг которой можно реализовать абстракцию сообщения или тот, в котором реализована только абстракция потока байтов, а всё остальное нужно реализовывать самому?
            • +1
              Прекращайте вестись на hype. Даже в рамках веб-сокетов это банальные запрос-ответ или стейт-машины.
              Я разве говорил про node.js? Я говорил просто про js. Вы, похоже, совсем не учитываете инструментарий языка при выборе решения задачи, а просто выбираете «что привычнее». Раз уже что-то написано на php, значит и дальше пишем на php, да? Но, я надеюсь, вам не надо объяснять всю колоссальную разницу между асинхронным программированием в php и js?

              А зачем их разделять?
              Затем, что эти процессы могут работать физически на разных машинах (что на Клавогонках они в данный момент и делают). Да и вообще, простите, как можно не разделять php-процессы в данном случае?
              • +2
                В словах Дмитрия есть некое здравое зерно, просто до него докопаться сложно. Именно поэтому само обсуждение в данном случае обречено на свалку, как, в последнее время и бывает во всех темах, касающихся node.js.
                • 0
                  Ну я повторюсь, я нигде не говорю о node.js, я говорю о языке javascript. Был бы традиционный веб-сервер на js, а не событийно-ориентированный, я бы все равно использовал его. А товарищ предлагает вообще использовать php, что для данной цели довольно дико.

                  Здравое зерно в его рассуждениях я не уловил ни по одному пункту. Выпады против redis вообще мне кажутся следствием довольно поверхностного понимания темы.
                  • +1
                    Вот потому, что беседа изначально обречена на свалку, вы друг друга совершенно не понимаете. Товарищ, на самом деле, далеко не дурак. И уж кого, кого… а его обвинить в любви к php точно нельзя. Он не предлагает ничего такого.

                    Я попробую перевести его посылку, как я ее понимаю, на человеческий конструктивный язык: он против node.js с одной стороны (и он правда аргументирует… в слегка эксцентричной манере, конечно, но что делать) и против нагромождения технологий. Если бы вы изначально все написали все на node, я думаю, он был бы более умеренным. И еще, мне кажется, он против того, что вы… можно сказать, поощряете своим публичным постом стремление нагромождать технологии в других разработчиках — тех, кто прочитает этот пост и подумает «да это нормально, все так делают».
                    • +1
                      Мне кажется, я понял эту мысль из его первого же коммента и сразу же предложил ему показать более минималистичный по количеству технологий способ решения данной задачи, что он до сих пор не сделал. Он предложил заменить одно звено другим — node.js на демон на php. При таком ходе количество технологий не уменьшается, потому что демон на php и традиционные cgi на php — это две большие разницы. Причем предложил делать это просто по историческим причинам, так как уже что-то работает на php, что я вообще не могу принять как показатель профессионализма.

                      Товарищ, возможно и не дурак, я вполне могу с этим согласиться, только в данном конкретном обсуждении он проявил либо интеллектуальную лень, либо желание завернуть тему в какую-то свою любимую сторону, не разобравшись в вопросе.
            • 0
              Разделять можно хотя бы для того, чтобы отделить сервис от данных.
              В эрланге, как мне известно, можно подменять отдельные участки кода, там же где этого нет искаропки, приходится выполнять разделение на несколько сервисов.
              Да и действительно, не очень php подходит для демонов, то, что какая-то морда сделана на php не значит, что на нем надо делать все.
          • +1
            phpdaemon и shm_*/msg_*, затрудняюсь сравнить их с node.js и redis по удобству и другим параметрам, только присматриваюсь к долгоживущим процессам, событийной модели и т. п., но они есть.
            • 0
              Они, разумеется, есть, это же php — самое большое программерское коммьюнити в мире! Но вот я лично вряд ли могу назвать их удобными.
              • +1
                Пробовали, рассматривали? Если да, то может напишите пост о впечатлениях?
                • 0
                  Вскользь смотрел. Меня сам по себе язык для этих целей не устраивает. Реальный выбор был только между Twisted и node.js. После некоторого исследования вопроса (например), остановился на node.js.
                  • +1
                    Наверное, не язык, а платформа? Если бы Зенд вместо «искаропочного» веб-сервера и множественных наследований запилили что-то типа Node.PHP прямо сейчас, ситуация с нелюбовью к PHP была бы сильно меньше. Особенно, если бы попутно ликвидировали старые нестыковки в именовании функций, например, и прочем. Даже если бы такой продукт тоже не умел бы работать со всеми ядрами из коробки, как Node.js… даже если бы они потеряли кучу «работающих» продуктов, написанных под старый PHP. Вместо этого они, действительно располагая ресурсами (и деньги у них есть, и разработчики) продолжают упорно двигаться по старым рельсам. Уж сколько я ни пытался у них узнать, почему так, до сих пор не смог получить ни одного ответа.

                    Простите… накипело
                    • 0
                      Нет-нет. Именно язык. Вы знаете, замыкания там всякие, прототипное наследование, variable scope и т.п.

                      В 5.3-5.4 ситуация чуть получше, но до критической отметки не достает.
                    • 0
                      Кстати, если очень хотите event-driven фреймворк на php, то лучше трясите Котерова, чтобы запилил в свою либу вебсокеты, может выйти что-нибудь толковое.
          • 0
            libevent позволяет общаться между процессами php. Но без крайней необходимости лучше этого не делать (лучше вообще не трогать эту штуку), проблем хватает. node.js действительно удобнее, проще в использовании и дает большую производительность.
        • +1
          Как я понимаю, для работы с вебсокетами по любому нужно отказываться от CGI модели в паре с сервером типа nginx или apache и писать демона. Так ли уж важно на чём он будет написан, если обоими языками (PHP и JS) и необходимыми фреймворками владеешь на одинаковом уровне?

          Если у нас отдельный демон и CGI-сайт на PHP, то по любому какую-то технологию межпроцессного взаимодействия использоваться придётся. Так ли велика разница какую именно, если пока ни одна в проекте не используется?

          Не, можно, конечно, использовать, скажем, phpdaemon для написания демона, а mysql в качестве средства IPC (собственно у меня он сейчас так и используется кроме всего прочего), но есть ли смысл держаться одно стека технологий, если другие, допустим, справляются лучше?
        • 0
          Вот чем отличаются отечественные IT ресурсы от зарубежных вот уже несколько лет — наличием таких обосрательных постов. Это не признак «наличия собственного мнения», а признак «отсутствия культуры».
        • 0
          А вы пробовали на PHP работать с вебсокетами?
          Я вот на phpdaemon 2 дня потратил, node.js оказался проще и надежнее в этом плане.
          • 0
            Можете рассказать об опыте? В идеале постом. Просто я и там, и там «хееловорды» писал по хаутушкам, большой разницы не заметил. Но все отличия JS от PHP изучал в процессе.
            • 0
              Я не настолько разобрался в phpdaemon, чтобы писать о нем))
              Вышло только заставить принимать запросы вебсокет-клиентов и выдавать ответы. Чуть-чуть сложнее чем в примерах. Broadcast сообщение от сервера клиентам вообще магически срабатывал 1 раз из 4х.
  • 0
    Интерес на дальнейшие статьи, само собой, есть.
    Скажите, а в сторону Dklab Realplexor не смотрели?
    Там уже есть готовое API для php. Правда там реализация, на сколько я понимаю, только через long polling.

    Ну и, на одной из конференций, ребята из геометрии немного ругались на Socket.IO (презентация)
    Из слайда Sucked.IO
    • Утечки памяти
    • Необъяснимые падения
    • Нестабильный Long polling
    • Проблемы с Flash Socket
    • Heartbeat’ы влияют на производительность и задерживают
    доставку сообщений
    • Хуевый дизайн приложения

    и предложили свой велосипед — Beseda. А после доклада, один из присутствующих в зале, очень хвалил решение от Котерова.
    • 0
      Смотрел давно, но всерьез не рассматривал, так как тут нужно именно полнодуплексное соединение. То, что описано в этой статье — лишь первый этап, в дальнейшем я планирую и основной игровой движок перетащить на эти технологии, что даст сильно больше возможностей. А там много двустороннего обмена, который не сделать в рамках обычных HTTP-соединений как в либе от Котерова.

      Если в Socket.IO найдутся какие-то принципиальные проблемы, то со временем я, возможно, просто откажусь от нее в сторону чистых вебсокетов и заявлю об отсутствии поддержки браузеров, где они не работают (таких скоро будет уже немного вне корпоративной среды).
      • 0
        Да, согласен, сокеты в вашем проекте более подходят.
        В целом конференция была полтора года назад, вполне возможно, что болезни уже вылечены.

        Проект у вас отличный, сейчас жена на нем играет-тренируется :)
      • +3
        Есть такая штука — SockJS. Идея проекта — дать разработчикам вебсокет-подобный объект на клиенте и он уже сам будет откатываться на поддерживаемые протоколы.

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

        А что до Socket.IO — он действительно очень плохой, его совершенно не поддерживают. Вот пример эпического бага, который открыт год: https://github.com/LearnBoost/socket.io/issues/438#issuecomment-10620702. Если кратко, то в клиенте есть race condition, который не могут вылечить уже год и клиент начинает DDOS'ить сервер.
        • 0
          Спасибо, посмотрю. Но статья не совсем о Socket.IO, всё же. Больше о вебсокетах как таковых.
          • +1
            Да, но если есть необходимость поддерживать старые браузеры: Socket.IO не самое лучшее решение. А идти с чистыми вебсокетами — еще хуже, IE8-9 еще популярен.

            Так уж сложилось что я с ним (и SockJS) уже около двух лет вожусь и Socket.IO совершенно не радует.
            • 0
              Обязательно попробую.
            • 0
              Я вот посмотрел на SockJS nodejs server. Не пойму а он умеет цепляться на Express или стандартный HTTP?
        • 0
          Прошу прощения за оффтопик, но означает ли это, что сокет.ио нельзя использовать в продакшене? Или есть какие-то определенные условия?
          • +1
            Использовать или не использовать в продакшене это каждый решает для себя сам исходя из своей задачи, тестов и… чужих мнений. У меня Socket.IO прекрасно работает и тоже скоро будет 2 года. Да были утечки, но они проявляются при определенных условиях. Я их нашел и сделал pull-request. Socket.IO просто считается перегруженным фичами. Он умеет отдавать своего же клиента сам. Есть поддержка подтвержающих коллбеков (кстати источник тех самых утечек). Есть автоподнятие соединения при пропадании связи. С SockJS придется все это реализовывать самостоятельно. Да меньше фичей меньше багов — есть возможность наваять своих. Но свои ж они как-то роднее :-)
            • 0
              pull request не приняли?
              • 0
                Пока нет. Там на самом деле 3 реквеста. Два из них противоречат друг другу, описание приложено. Надо принять решение. Видимо облом вникать.
              • 0
                Ну реквестам не 2 года. Они связаны с коллбеками, которые я начал использовать недавно и заметил утечку. У вас коллбеков нет, как я вижу. А в самой Socket.IO все равно пришлось копаться потому что у меня клиент не стандартый. На MS ActiveScripting, ну по стути это движок от IE 8.0, только без браузера. Вместо браузера и DOM мои объекты. Так что я в него вкрутил WebSockets и делал там обертку, чтоб Socket.IO cliеnt думал, что он в браузере.
                • 0
                  Коллбеки у меня в реальном коде, на самом деле, есть. Пойду медитировать над реквестами.
          • 0
            Лучше не использовать — сервера ложатся от нагрузки из за бага указанного по ссылке выше. Этот самый серьезный, по мелочи там хватает разного.

            Сейчас все ждут Socket.IO поверх Engine.IO (Engine.IO это SockJS, но от разработчиков Socket.IO) или переходят на что-то более стабильное (Faye, SockJS, etc).

            Что до SockJS… В плане функциональности — это вебсокеты и ничего больше. Нет событий, нет каналов из коробки (но есть отдельный мультиплексор — https://github.com/sockjs/websocket-multiplex), нет автоматического реконнекта, нет комнат и тому подобного.

            И, если честно это хорошо. Очень сложно угадать что потребуется разработчикам: как группировать клиентов, как должен работать реконнект и т.д.
            • 0
              Ну мне важна поддержка редиса и все. Комнаты я сам контролирую. Вопрос в другом — при каких условиях проявляется описанный выше баг? Ведь если все так плохо, то почему еще все не начали использовать другое решение?
              • +1
                Почему не начали?

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

                Для «поиграться» (всякие небольшие проектики, proof-of-concept, etc) вполне себе нормально работают на Socket.IO. Там не такие нагрузки, что бы спровоцировать этот race condition.
                • 0
                  Не сочтите за наглость, можно пруфы того, что переезжают? Если так, то насколько сложно переехать и на что?
                  • +1
                    По ссылке выше есть немного (в тикете Socket.IO).

                    PythonAnywhere (облачная питоновская консоль) переехала. Одна из причин была стабильность Socket.IO, вторая — у SockJS latency меньше. blog.pythonanywhere.com/27/

                    Знаю несколько человек, которые долго долбили багтрекер Socket.IO (@dominiek, тоже есть в том тикете), перешли со своими проектами на SockJS.

                    Metor тот же (который на node.js) сначала был на socket.io, потом его выпилили и сделали SockJS.

                    Ну и так далее.

                    Переезд — смотря сколько функционала завязано на фичи самого socket.io. Если используются event'ы — прийдется их руками сделать (или найти либу, вроде кто-то делал).
  • +1
    ошибочно вставленный коммент
  • 0
    Вброс, и могу ошибаться. Но разве веб-сокеты не были реализованы ~10 лет назад во флэше? Или там что-то другое?
    • 0
      Про флеш я в топике отдельно пояснил. Не дело это, для одного лишь транспорта использовать флеш, когда нигде больше он не нужен. Кроме того, я лично с флешем не дружу совсем. Кроме того, насколько я знаю, у флеша есть некоторые ограничения вроде необходимости открывать 843 порт, и следовательно, напороться на проблемы с прокси-серверами.
      • 0
        нет там ничего такого, и 843 порт не нужен — просто флеш при соединении к порту ниже 1024 ( а логично и проверено что для корректной работы и в корпоративной среде тоже, лучше использовать 443 порт), он запрашивает полиси файл. При этом запрос идет сначала на 843 как стандартный порт, а потом по тому же порту, что и соединения.
    • 0
      Была реализована другая технология полнодуплексного, афаик, обмена сообщениями между сервером и браузером. Но к стандарту веб-соектов она никакого отношения не имеет. Это две разные технологии с одним или схожим назначением. Технология, используемая во Флэше, частенько используется для эмуляции веб-сокетов, если браузер её не поддерживает. Собственно в статье она упоминается, 4% соединений идут через неё (а 90% через веб-сокеты).
      • 0
        кстати, говоря, флешевый сокет даже гораздо удобнее — там нет никаких ограничений и протоколов, просто обычный сокет.
        • 0
          Более гибкое скорее в следствии низкоуровневости. Как сравнивать Си и какой-нибудь высокоуровневый язык — кто из них удобнее?

          Если мы посредством костыля флэша вводим в JS возможность работать с сокетами, то многое придётся придумывать и реализовывать самим и далеко не факт, что это получится лучше чем получилось у дядей из W3C и производителей браузеров.
          • 0
            ну, превоначальные протоколы ws были еще норм, а потом все усложнилось да так, что без либы сторонней и не реализуешь нормально. И хендшейк странный и фрейминг — очень часто, если не надо особых наворотов, на сокетах обычных куда проще. Хотя я не умаляю ws — это хорошо и отлично. Лишь бы кто выпустил вменяемую библиотеку для встраивания в существующий проект, а не мощные навернутые системы
  • 0
    Кстати, ещё такой вопрос.
    Через сокеты вы клиенту отправляете сообщения с сервера.
    А как происходит отправка сообщений от клиента на сервер? Через ajax?
    • 0
      Не знаю как автора, но вебсокеты двухсторонние можно и на сервер через них слать.
      • 0
        А как, тогда, быстро передать данные в php скрипт?
        • 0
          почему не поднять веб-сокет сервер на РНР?
          • 0
            Кстати, а можно пример такого сервера?

            В целом, у автора сервер на node.js, общение между php и node.js происходит через redis
            При отправке данных от php — вопросов нет. Это и описано в статье. А вот как эти данные получить (если они отправлены через сокет), непонятно.
            • +1
              Нет, у автора все отлично и правильно — через редис это самый хороший вариант, который и я использую и всем рекомендую ) тем более что редис можно еще много как использовать.

              Пример? да запросто:

              socketo.me
              github.com/kakserpom/phpdaemon (сайт у них что-то тормозит, но автор есть и на хабре — habrahabr.ru/post/79377/) и там есть из коробки вебсокеты.
              • 0
                Я не говорю, что у него плохо :)
                По ряду причин я выбрал для этого node.js — событийно-ориентированная модель и хорошо развитые коллбэки в javascript идеально подошли для этой задачи.
                Общей средой общения между php-бэкэндом и сервером на node.js стали pubsub-каналы redis.


                Я просто не в курсе, при отправке сообщения от клиента мы сможем это сообщение переслать в php скрипт?

                client -> node.js -> redis -> ??? -> php

                Кстати, спасибо за ссылки!
                • 0
                  а, простите, не до конца понял вопрос.

                  Есть несколько костыльных вариантов, как я вижу:

                  — напрямую вызов РНР (по сути, через exec — это если код, обрабатывающий данные, обязательно РНР)
                  — посредством локального HTTP интерфейса (по сути, нода выступает почти прокси — приняла -> немного обработала -> если надо, сделала вызов localhost/script.php — зато такой вариант несколько быстрее и гибкий
                  — модификация первого метода, использую тот же FastCGI для общения с РНР.
                  • 0
                    Либо тупо отправлять через ajax от клиента напрямую в php.
                    Опять же, если через ajax, то ответ идет через сокет?
                    client -> ajax -> php -> redis -> node.js -> client
                    или сам php отвечает?
                    client -> ajax -> php -> client

                    Вот я и хотел уточнить, как это реализовано у автора.
                    • 0
                      У меня реализовано именно так, как пишет aleks_raiden — POST-запрос из node.js на локальный порт веб-сервера. Постепенно я буду от этого уходить, переписывая куски логики в самом node.js.
            • 0
              А реакция какая ожидается от PHP при получении клиентских данных по веб-сокету? Должен ли быть ответ клиенту, сформированный PHP? Должна ли быть реакция PHP мгновенной?

              Если рассматривать простейший случай (ответ не требуется или достаточно лишь статуса, что данные успешно переданы в php, обработка не должна быть мгновенной и т. п.), то демон, обслуживающий сокеты просто пишет куда-то (файл, разделяемая память, субд, сервер сообщений, сервер очередей и т. п.) данные для php, рапортует если нужно о статусе, а уж php обрабытывает эти данные когда «захочет» (по запросу пользователя, по запросу скрипта в браузере, по крону и т. п.).
              • 0
                Сценарий:
                Во время гонки была нажата клавиша «а»

                Естественно надо это дело обработать и, как можно скорее, сообщить другим участникам гонки, что машина продвинулась.

                В простейшем случае, я бы данные от клиента отправлял напрямую в php скрипт (ajax), а другим участникам рассказывал бы через сокет. Но, в случае с клавогонками можно заддосить сервер, ибо каждую нажатую клавишу надо отправить на сервер и таких клавиш много (от всех игроков онлайн).
                • 0
                  Вот чтобы не ддосить сервер, надо отправлять не через ajax, а по сокету, там оверхед поменьше. А node.js передаст, кому надо. Может, даже сразу в базу что-то запишет, а php по завершению заберет агрегированные данные. Ну или POST на скрипт.

                  Хотя на каждую клавишу слать событие — это, конечно, жестоко.
                • 0
                  Я бы вообще задумался о необходимости PHP (или другого CGI/CLI-скрипта) в данном сценарии. Вернее о необходимости полной синхронной обработки. Получили через веб-сокет сообщение от клиентском событии, просчитали необходимые здесь и сейчас для отправки результаты (позицию машинки или даже дельту её смещения, если явного финиша нет), вытащили из памяти список тех, кому надо его отправить (явно или имя общего канала), отправили, сделали, если необходимо, запись в базу или положили сообщение в очередь для более поздней синхронной обработки (по запросу пользователями или таймеру) и спим до следующего события. Причём спать ложимся как только дали команду на рассылку и запись в базу или очередь. А вот когда заезд завершен, можно обычным php скриптом посчитать статистику, определить победителя, дать ему награду и т. п. обработав все записи о клиентских событиях за один проход.
    • 0
      вебсокеты являются двунаправленным каналом.
  • +3
    Думаю для одного небольшого проекта попробовать вот такую штуку:
    github.com/wandenberg/nginx-push-stream-module

    Бонусы:
    — вся мощь nginx в обработке асинхронных запросов
    — поддерживает несколько способов раздачи одновременно — polling, long-polling, eventsource, websockets
    — в комплекте есть js-библиотека, реализующая их все и умеющая graceful degradation, но можно и самому все сделать.
    — можно использовать как простенький сервер очередей
    — включен в пакет nginx на dotdeb, то есть ставится без свистоплясок одной командой или уже есть

    Идея в том, чтобы всю раздачу сообщений пользователям свалить на полностью готовое решение, а существующий бэкэнд сделать максимально тупым, чтобы он только постил апдейты в канал.
    Отпадает необходимость городить отдельный сервер на node.js+redis и подобном.

    Обратный канал оставить на классическом xhr+fastcgi, он все равно нужен, если делать graceful degradation.

    Теоретически модуль умеет принимать publish в канал с клиентов, подключившихся через вебсокеты, но реализовано это как-то коряво (publish делается в тот же канал, на который была подписка).
    Если очень надо, можно, наверное, открыть второе websocket-соединение на отдельный канал чисто на отправку, хоть это и костыль.
    Тогда можно и fastcgi выкинуть совсем, читать сервером сообщения, прицепившись локально к nginx через обычный http streaming к этому каналу.
    • 0
      Ну, если вы действительно хотите писать реагирование на входящие от клиентов события на php, то почему бы и нет. Как по мне, так js для этого подходит куда лучше.
      • 0
        Я разве где-то упомянул php?
        Можно, на самом деле, и обычный xhr post засовывать в ту же очередь вместо fastcgi, и затем чем прицепились к очереди, тем и читаем, хоть bash-скриптом.
        Хотя, по-моему, чтобы не плодить сущности, удобнее это делать на том же языке, на котором написана остальная логика.
        Раз уж не надо самому возиться с многопоточностью (эта работа взвалена на откомпилированный сишный модуль), почему бы и нет.
        Если воркер все же нужен многопоточный, то непонятно, чем плох fastcgi, который все равно уже есть.
        • 0
          Возможно, для какого-то узкого круга задач это будет более эффективно, да. У меня же тут планы завязаны на перенос большой части логики в node.js, оттого так.
    • 0
      Интересно, но как-то кажется, что архитектуру это не упростит, если добавить, например, аутенфикацию и авторизацию.
      • 0
        Да, решение больше ориентировано на broadcast одного канала всем желающим, чтобы application-серверу было вообще пофигу, сколько их там висит.

        Персональные каналы я бы делал так:
        — id канала — это хэш наподобие session id, можно даже его и использовать, модуль умеет читать id канала из кук
        — каждый клиент подписывается одновременно на два канала — общий и свой персональный, модуль это опять же умеет делать в рамках одного соединения.
        — если сессия стала невалидна — убиваем канал с сервера

        Безопасность получается на том же уровне, что и остального приложения (угон id канала равносилен угону сессии), если надо — завернули все в https средствами того же nginx.
  • +1
    А зачем вам flashsocket & jsonppolling?

    и Opera (кроме мобильных) и IE (за 6-й, вот точно не скажу) — прекрасно живут с xhr-polling.

    У нас стабильно xhr-polling + websockets
    • +1
      Почему xhr-polling плох в моем случае, я описал в самой статье. Очень частые запросы и оверхед.
      • 0
        Понятно. Мы решили уменьшить количество сущностей.
        Всё равно сокетная часть размазана по кластеру и там уже не так страшно 40к одновременных будет, или 70к…
        • 0
          А вы — это кто, если не секрет? Интересно посмотреть на кухню.
          • +1
            Надеюсь что к понедельнику допишу статью и поделюсь ссылкой.
            Увы по основному high load — жёсткий NDA.
            Кухня — erlang ;-)
  • +1
    А какая у вас нагрузка на Socket.IO выходит? И на каком сервере все крутится?
    А то поначалу оно обычно всегда нравится и удобно, а потом оказывается, что течет и имеет фатальные проблемы с производительностью при серьезных нагрузках.
    • 0
      Socket.IO используется в больших проектах. Даже если с ним будут проблемы, от него можно не сильно болезненно отказаться, а голый node.js используется не в больших, а в очень больших проектах и замечательно масштабируется.

      Сейчас вебсокетовый сервер работает на Intel Core2Quad Q8300 2.5GHz, занимает около 120 мб памяти и не более 8% цпу при нагрузке, которую вы примерно можете оценить сами на сайте.
      • +1
        Насчет замечательной масштабируемости можно поспорить. Все-таки V8 однопоточный по природе своей. И родной нодовый cluster имеет забавные побочные эффекты из-за этого.
        А Socket.IO имеет их еще больше, потому что изначально был расчитан на одно ядро, а потом туда воткнули redis, который местами забыли прикрутить, отчего то теряются сокеты, то наоборот плодятся не в том потоке, где надо.

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

        А нагрузку на сайте оценить к сожалению не получится. Как показала практика, socket.io довольно легко держит и тысячу одновременных соединений, если они уже установлены. Самой дорогой операцией оказался коннект/дисконнект. Вот и интересно, сколько их у вас в единицу времени? Если считали, конечно.
        • 0
          Так и пусть однопоточный. Что при отсутствии разделяемых глобальных данных мешает запускать любое количество нод позади балансировщика?

          Самой дорогой операцией оказался коннект/дисконнект. Вот и интересно, сколько их у вас в единицу времени? Если считали, конечно.

          Немного. Примерно 30 в минуту. Но я сомневаюсь, что на это уходит большая часть производительности, потому что сообщения льются в канал непрерывным потоком, это грузит сильнее.
          • +2
            Любое количество нод запустить не проблема. Но проблемой становится синхронизация их между собой. Особенно, если речь идет, например, о пользователях, которые должны между собой общаться, независимо от того, к какому экземпляру ноды они прицепились при коннекте.

            Непрерывный поток будет даже без сообщений. Потому что каждому клиенту Socket.IO посылает heartbeat и ожидает отклика. Ну при 30 коннектах в минуту в принципе еще все хорошо должно быть.
            • 0
              Ну а синхронизация решается опять же различными технологиями разделяемой памяти или этот же pubsub. Решать эту задачу на внутрипроцессном уровне в node.js противопоказано в принципе.

              Непрерывный поток будет даже без сообщений. Потому что каждому клиенту Socket.IO посылает heartbeat и ожидает отклика. Ну при 30 коннектах в минуту в принципе еще все хорошо должно быть.

              Я имею в виду, нагрузку на саму ноду, а не на Socket.IO (видимую в top).
              Да, сейчас нагрузка пока никакая в общем-то. Будем смотреть внимательнее, когда на вебсокеты переедут другие части движка.
  • +1
    Спасибо за интересный пример использования вебсокетов.
    Интерес к дальнейшим статьям есть, особенно к AngularJS.
    • 0
      Уже есть статьи по этой теме, но и вообще от себя скажу что штука хорошая стоит использовать, опять же кантора серьезная :)

      Хотя новые статьи будут не лишними.
  • 0
    Спасибо за статью.
  • +2
    Интересно будет почитать про Angular.js, особено если есть возможность сравнить в статье с Knockout.js — плюсы, минусы, юзкейсы того и другого.
    • +1
      Присоединяюсь, все познается в сравнении :-)
      • +1
        По моим ощущениям основная разница — knockout.js для отслеживания изменений в модели дата-биндинга использует сложную систему коллбэков (observables) и отслеживания зависимостей данных друг от друга; а angular.js делает простую проверку на измененность данных (dirty check) каждый цикл по всем данным в модели вообще. И как по мне, так второй способ гораздо лучше в большинстве случаев.
  • 0
    Во многих проектах для реалтайма использую dklab.ru/lib/dklab_realplexor/ Помоему это намного проще чем вебсокеты которые работают только в хроме.
    • 0
      Из статьи же видно, что при доле Хрома в 51%, используют вебсокеты 90% клиентов, то есть ещё 39% браузеров, что больше доли фокса и оперы вместе взятых.
    • 0
      Вебсокеты работают в:

      Firefox 6+
      Chrome 4+
      Safari 6+
      Opera 12.10+
      IE10+

      Realplexor использует xhr-polling, что применимо далеко не во всех случаях. Например, непрерывный стриминг сообщений с клиента на сервер на нем в принципе сделать нельзя.
    • 0
      Comet уже не тот. Зря чтоли трудились над стандартами веб-сокетов и HTML5 SSE.
  • 0
    Все это прекрасно, кто бы написал как вебсокеты нормально логировать при балансинге на несколько нод. А то для «пет» проектов хорошо, а что дальше делать с ними когда начнешь расти.
    • 0
      Так здесь, как раз, redis для этого
    • 0
      А в чем, собственно, проблема-то? Мне кажется, уж логирование — это последнее, что должно вызывать трудности.
      • 0
        Я имел ввиду не логирование не на стороне бекенда с самим вебсокетами, а именно прокси логирование. Как минимум ддос и туда ж можно пустить.
        • 0
          Все равно не понял. Логирование подключенных клиентов? IP-адреса?
  • +1
    Как-то навернул в своем дипломном проекте систему с брокером AMQP в качестве промежуточного звена (эдакий pub/sub). Необходимо было в реалтайме оповещять клиентов о новой информации, которую скрапит веб-паук. Даже заработало.

    image

    После того, как я все написал, стало понятно, что архитектура не самая оптимальная.
    • +1
      Вот это я понимаю, нагромождение технологий. :)
      • +1
        Если отбросить клиентскую часть, то: AMQ server, база postgresSQL, (веб?) сервер на питоне, паук на питоне и memcached. В отличие от топика: 1 сервверный язык, а не 2; добавился memcached; не видно апача/nginx-а.

        По мне не сложнее чем в топике, просто картинка страшнее из-за деталей вроде «разграничения прав» или названий библиотек.

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