Особенности применения
Websocket
на примере работы в ERP
Фролов Александр
14.06.2013г.
Актуальность данных
• Данные на странице — устаревают;
• основании устаревших данных можно принять не верное
решение;
• Не верное решение ведёт в конечном счёте к финансовым
потерям, если это приложение решает бизнес задачи.
• Выход? Нужно получать данные от сервера в момент их
поступления на сервер;
• Нужно иметь возможность инициировать отправку данных
сервером.
Как быть, каким способом
актуализировать данные?
• Первый тривиальный способ — запрашивать каждые n секунд
сервер о новых данных.
При этом чем чаще — тем быстрее получаем обновление
данных.
• Простой подсчёт показывает: в ERP системе за сутки будет
генерировать 2,5 миллиона запросов. КПД от работы системы —
стремится к нулю.
Ограничения:
согласно спецификации HTTP 1.1
браузер не должен иметь более двух
соединений одновременно
• Если открыто более двух страниц в браузере очень вероятны
случаи, когда запросы на обновление не проходят;
• Применение других способов, отличных от простых запросов на
обновления так же требует учитывать это обстоятельство;
Comet (программирование)
• Модели работы веб приложений, при которых постоянное HTTP
соединение позволяет веб-серверу отправлять (push) данные
браузеру без дополнительного запроса со стороны браузера,
называют Comet технологиями, а приложения, которые
реализуют такую модель — comet приложениями.
• Благодаря comet-приложениям клиент в режиме реального
времени может взаимодействовать с сервером, опираясь на
постоянное или long polling соединение HTTP.
Реализации comet технологий
• Потоковые: открывается постоянное соединение между
клиентом и сервером.
• Long polling (длительное соединения): открывается соединение
и ожидается ответ по таймауту или до таймаута, после чего
соединение переоткрывается
Потоковые: открывается постоянное
соединение между клиентом и сервером.
Скрытый IFRAME
Постоянно в IFRAME шлются данные, например, строки с пустым
комментарием, и в нужный момент сервер передает javascript
строку, которая сразу выполняется. Из минусов можно
выделить не возможность нормальной обработки ошибок и не
возможность отследить реакцию на передачу данных со
стороны сервера.
XMLHttpRequest
У ряда браузеров (FF, WebKit, IE10) имеется возможность получать
multipart response — ответ порциями, тем самым очередную
порцию отсылаем тогда, когда нужно серверу. Особого
распространения не получило.
Ajax с long polling
Браузер делает Ajax запрос на сервер, который остается
открытым, пока сервер не отправит данные. По таймауту
пересоздается соединение.
Script tag long polling
Подгружается динамически javascript файлы, в которых
передаются данные по мере их поступления. Как только один
файл «загрузился», подгружается следующий файл.
WebSocket
WebSocket - веб-технология, обеспечивает полнодуплексный
канал связи через одно соединение TCP. Протокол WebSocket
был стандартизирован IETF RFC 6455 в 2011 году. WebSocket
соответствует стандартам W3C.
Базовое использование
WebSocket на стороне клиента:
<script>
ws = new WebSocket("ws://site.com/ws");
// обработка события, при установки соединения
ws.onopen = function() { alert("Connection opened...") };
// обработка события, при закрытии соединения
ws.onclose = function() { alert("Connection closed...") };
// обработка события получения сообщение через веб-сокет
ws.onmessage = function(e) { alert(e.data); };
</script>
Немного деталей :)
Процесс открытия WS выглядит на данный
момент следующим образом.
В начале идёт HTTP-запрос:
GET /ws HTTP/1.1
Host: site.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13
Origin: http://site.com
Если сервер поддерживает WS,
то то ответ будет:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Key содержит случайное значение,
закодированное Base64.
Sec-WebSocket-Accept вычисляется путём
конкатенации Sec-WebSocket-Key и «magic string»:
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
$SecWebSocketAccept = base64_encode(sha1($SecWebSocketKey .
'258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
Существует две модификации протокола: ws:// и wss://,
это по смыслу почти как http:// и https://,
то есть wss:// - шифрованное соединение.
Формат передаваемых текстовых данных
0x00 <строка в кодировке UTF-8> 0xFF
просто строка текста — последовательность байт, к которой
спереди приставлен нулевой байт 0x00, а в конце — 0xFF.
И все — никаких заголовков, метаданных.
Передача и бинарных данных
Длина записывается по следующим правилам: Каждый байт в
указании длины рассматривается по частям: самый старший бит
указывает является ли этот байт последним (0) либо же за ним
есть другие (1), а младшие 7 битов содержат собственно
данные.
0x80 <длина - один или несколько байт> <тело сообщения>
1 0 0 0 1 1 1 01 0 0 0 0 1 1 0 0 0 0 1 0 1 1 0
Какими браузерами поддерживается?
Protocol IE FF FF
(android)
Chrome Safari Opera
hixie-75 4 5.0.0
hixie-76
hybi-00
4 6 5.0.1 11
7 hybi-07 6
8 hybi-10 7 7 14
13 RFC 6455 10 11 11 16 6 12.10
Организации работы WS
Различные реализации серверов на многих платформах:
node.js, Pyton, Ruby on Rails, PHP...
Из PHP Open Source проектов можно отметить довольно динамично
развивающийся проект phpDeamon. Но это универсальный
всеядный комбайн.
Но в реальности используем более легкую реализацию, которую
проще проверить и адаптировать под свои нужды.
(https://github.com/lemmingzshadow/php-websocket)
Принцип работы WS сервера на php
- запуск в цикле опроса открытых портов.
while(true) {
foreach($sockets as $socket) {
// read socket
$data = readBuffer($socket);
process_data($cleint[(int)$socket], $data);
}
}
Обычная схема работы
БД
W
SК
Схема быстрого внедрения WS
БД
W
S
К2
Кn
К1
W
S
S
Ajax
mess
mess
mess
mess
Mess — сообщение
Об изменениях, для
всех одно и тоже,
фильтрация «нужен /
не нужен» или на стороне
клиента или решение об
Отправки mess принимает
WSS исходя из типа
страницы на строне клиента.
Продвинутая схема использования WS
БД
W
S
К2
Кn
К1
W
S
S
Ajax
mess
mn
m2
m1
mess — сообщение
об изменениях
M1, M2, … Mn —
подготовленные для
каждого типа страниц
сообщения, включающие
все специфические
данные. Не достающие
данные добираются из БД.
Полная интеграция WS
БД
W
S
К2
Кn
К1
W
S
S
HTTP
m0
mn
m2
m1
Конкурирующие запросы
• С ростом количества запросов может быть ситуация, когда
данные более свежего запроса придут позже, чем данные
более старого запроса.
• Необходимо посылать с данными на изменения временные
метки, чтобы обеспечить минимальную защиту от подобных
коллизий;
• Так же нужна временная метка о начале работы с данными, то
есть когда пришли данные, которые отредактировали;
• Две временные метки позволяют сравнить данные, которые
меняем с данными которые находятся в БД, а так же их
«свежесть» и в случае чего не допустить перезатирания новых
данных — старыми. При этом клиенту, приславшего
конфликтный запрос — отправлять уведомление с просьбой
проверки данных + обновленные данные.
Стоит ли использовать
более серьёзный подход?
• Можно использовать систему разделения ресурсов,
флаги, семафоры...
• Внедрение связано со значительным усложнением
всей системы;
• От пользователе потребуются дополнительные усилия в работе;
• Необходимо четко очень реальную необходимость внедрения.
Пишите логи
В обязательном порядке записываете в логах
обо всех изменениях в системе:
• кто
• когда
• что
• старое значение
• новое значение
Собирайте мусор в WSS

WSS представляет собой один работающий процесс по
приему, обработке и отправке сообщений. Со временем не
используемые переменные постепенно забивают память вплоть
максимально возможного лимита для php процесса. Чтобы
этого не случилось необходимо подчищать за собой
переменные и объекты (gc_enble(); gc_collect_cycles();
gc_disable; )
Перегружайте WSS иногда :)
gc_collect_cycles() помогает, но объем используемой памяти всё
равно может неуклонно расти.
Поэтому проверяйте объём используемой памяти, и в случае
превышения определенного лимита инициируйте перезагрузку
WSS.
Пример упрощенного кода ядра WSS
$flag = true;
While ($flag) {
If (time() - $time_last_check >= 60 сек) {
If (get_file_flag() == 1) {
$flag = false;
} else if (memory_get_peak_usage()/1024/1024
>= ini_get("memory_limit") * 0.8) {
send_notice(); set_timer_to_reboot();
$flag = false();
}
}
}
Возможности «виртуального» кэша
• Так как процесс обрабатывающий сообщения один, то и
сохраняя данные в определенный массив/объект можно
получить нечто на подобие кэша с актуальными данными;
• Следует учитывать ограничения на объём памяти и не забывать
подчищать такой кэш.
• Определив экспериментальным путем суточные потребности
ERP системы были увеличены лимиты с 128Мб, до 1Гб памяти
для WSS, тем самым все необходимые для работы данные в
результате находились в кэше.
• В PHP 5.3.0 можно указывать в php.ini memory_limit 1G
Ссылки на ресурсы, статьи, GitHub
http://en.wikipedia.org/wiki/Comet_(programming)
http://en.wikipedia.org/wiki/WebSocket
https://github.com/nicokaiser/php-websocket
http://nginx.com/news/nginx-websockets.html
https://github.com/disconnect/apache-websocket
https://github.com/kakserpom/phpdaemon
https://github.com/nicokaiser/php-websocket
https://github.com/hoaproject/Websocket
https://github.com/lemmingzshadow/php-websocket
Докладчик: Фролов Александр
alex.frolov@gmail.com
@alex__frolov
https://www.facebook.com/frolov.alexander

DevConf2013: Особенности применения WebSocket на примере работы в ERP системе.

  • 1.
    Особенности применения Websocket на примереработы в ERP Фролов Александр 14.06.2013г.
  • 2.
    Актуальность данных • Данныена странице — устаревают; • основании устаревших данных можно принять не верное решение; • Не верное решение ведёт в конечном счёте к финансовым потерям, если это приложение решает бизнес задачи. • Выход? Нужно получать данные от сервера в момент их поступления на сервер; • Нужно иметь возможность инициировать отправку данных сервером.
  • 3.
    Как быть, какимспособом актуализировать данные? • Первый тривиальный способ — запрашивать каждые n секунд сервер о новых данных. При этом чем чаще — тем быстрее получаем обновление данных. • Простой подсчёт показывает: в ERP системе за сутки будет генерировать 2,5 миллиона запросов. КПД от работы системы — стремится к нулю.
  • 4.
    Ограничения: согласно спецификации HTTP1.1 браузер не должен иметь более двух соединений одновременно • Если открыто более двух страниц в браузере очень вероятны случаи, когда запросы на обновление не проходят; • Применение других способов, отличных от простых запросов на обновления так же требует учитывать это обстоятельство;
  • 5.
    Comet (программирование) • Моделиработы веб приложений, при которых постоянное HTTP соединение позволяет веб-серверу отправлять (push) данные браузеру без дополнительного запроса со стороны браузера, называют Comet технологиями, а приложения, которые реализуют такую модель — comet приложениями. • Благодаря comet-приложениям клиент в режиме реального времени может взаимодействовать с сервером, опираясь на постоянное или long polling соединение HTTP.
  • 6.
    Реализации comet технологий •Потоковые: открывается постоянное соединение между клиентом и сервером. • Long polling (длительное соединения): открывается соединение и ожидается ответ по таймауту или до таймаута, после чего соединение переоткрывается
  • 7.
    Потоковые: открывается постоянное соединениемежду клиентом и сервером. Скрытый IFRAME Постоянно в IFRAME шлются данные, например, строки с пустым комментарием, и в нужный момент сервер передает javascript строку, которая сразу выполняется. Из минусов можно выделить не возможность нормальной обработки ошибок и не возможность отследить реакцию на передачу данных со стороны сервера.
  • 8.
    XMLHttpRequest У ряда браузеров(FF, WebKit, IE10) имеется возможность получать multipart response — ответ порциями, тем самым очередную порцию отсылаем тогда, когда нужно серверу. Особого распространения не получило.
  • 9.
    Ajax с longpolling Браузер делает Ajax запрос на сервер, который остается открытым, пока сервер не отправит данные. По таймауту пересоздается соединение.
  • 10.
    Script tag longpolling Подгружается динамически javascript файлы, в которых передаются данные по мере их поступления. Как только один файл «загрузился», подгружается следующий файл.
  • 11.
    WebSocket WebSocket - веб-технология,обеспечивает полнодуплексный канал связи через одно соединение TCP. Протокол WebSocket был стандартизирован IETF RFC 6455 в 2011 году. WebSocket соответствует стандартам W3C.
  • 12.
    Базовое использование WebSocket настороне клиента: <script> ws = new WebSocket("ws://site.com/ws"); // обработка события, при установки соединения ws.onopen = function() { alert("Connection opened...") }; // обработка события, при закрытии соединения ws.onclose = function() { alert("Connection closed...") }; // обработка события получения сообщение через веб-сокет ws.onmessage = function(e) { alert(e.data); }; </script>
  • 13.
    Немного деталей :) Процессоткрытия WS выглядит на данный момент следующим образом.
  • 14.
    В начале идётHTTP-запрос: GET /ws HTTP/1.1 Host: site.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat Sec-WebSocket-Version: 13 Origin: http://site.com
  • 15.
    Если сервер поддерживаетWS, то то ответ будет: HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat
  • 16.
    Sec-WebSocket-Key содержит случайноезначение, закодированное Base64. Sec-WebSocket-Accept вычисляется путём конкатенации Sec-WebSocket-Key и «magic string»: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 $SecWebSocketAccept = base64_encode(sha1($SecWebSocketKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)); Существует две модификации протокола: ws:// и wss://, это по смыслу почти как http:// и https://, то есть wss:// - шифрованное соединение.
  • 17.
    Формат передаваемых текстовыхданных 0x00 <строка в кодировке UTF-8> 0xFF просто строка текста — последовательность байт, к которой спереди приставлен нулевой байт 0x00, а в конце — 0xFF. И все — никаких заголовков, метаданных.
  • 18.
    Передача и бинарныхданных Длина записывается по следующим правилам: Каждый байт в указании длины рассматривается по частям: самый старший бит указывает является ли этот байт последним (0) либо же за ним есть другие (1), а младшие 7 битов содержат собственно данные. 0x80 <длина - один или несколько байт> <тело сообщения> 1 0 0 0 1 1 1 01 0 0 0 0 1 1 0 0 0 0 1 0 1 1 0
  • 19.
    Какими браузерами поддерживается? ProtocolIE FF FF (android) Chrome Safari Opera hixie-75 4 5.0.0 hixie-76 hybi-00 4 6 5.0.1 11 7 hybi-07 6 8 hybi-10 7 7 14 13 RFC 6455 10 11 11 16 6 12.10
  • 20.
    Организации работы WS Различныереализации серверов на многих платформах: node.js, Pyton, Ruby on Rails, PHP... Из PHP Open Source проектов можно отметить довольно динамично развивающийся проект phpDeamon. Но это универсальный всеядный комбайн. Но в реальности используем более легкую реализацию, которую проще проверить и адаптировать под свои нужды. (https://github.com/lemmingzshadow/php-websocket)
  • 21.
    Принцип работы WSсервера на php - запуск в цикле опроса открытых портов. while(true) { foreach($sockets as $socket) { // read socket $data = readBuffer($socket); process_data($cleint[(int)$socket], $data); } }
  • 22.
  • 23.
    Схема быстрого внедренияWS БД W S К2 Кn К1 W S S Ajax mess mess mess mess Mess — сообщение Об изменениях, для всех одно и тоже, фильтрация «нужен / не нужен» или на стороне клиента или решение об Отправки mess принимает WSS исходя из типа страницы на строне клиента.
  • 24.
    Продвинутая схема использованияWS БД W S К2 Кn К1 W S S Ajax mess mn m2 m1 mess — сообщение об изменениях M1, M2, … Mn — подготовленные для каждого типа страниц сообщения, включающие все специфические данные. Не достающие данные добираются из БД.
  • 25.
  • 26.
    Конкурирующие запросы • Сростом количества запросов может быть ситуация, когда данные более свежего запроса придут позже, чем данные более старого запроса. • Необходимо посылать с данными на изменения временные метки, чтобы обеспечить минимальную защиту от подобных коллизий; • Так же нужна временная метка о начале работы с данными, то есть когда пришли данные, которые отредактировали; • Две временные метки позволяют сравнить данные, которые меняем с данными которые находятся в БД, а так же их «свежесть» и в случае чего не допустить перезатирания новых данных — старыми. При этом клиенту, приславшего конфликтный запрос — отправлять уведомление с просьбой проверки данных + обновленные данные.
  • 27.
    Стоит ли использовать болеесерьёзный подход? • Можно использовать систему разделения ресурсов, флаги, семафоры... • Внедрение связано со значительным усложнением всей системы; • От пользователе потребуются дополнительные усилия в работе; • Необходимо четко очень реальную необходимость внедрения.
  • 28.
    Пишите логи В обязательномпорядке записываете в логах обо всех изменениях в системе: • кто • когда • что • старое значение • новое значение
  • 29.
    Собирайте мусор вWSS  WSS представляет собой один работающий процесс по приему, обработке и отправке сообщений. Со временем не используемые переменные постепенно забивают память вплоть максимально возможного лимита для php процесса. Чтобы этого не случилось необходимо подчищать за собой переменные и объекты (gc_enble(); gc_collect_cycles(); gc_disable; )
  • 30.
    Перегружайте WSS иногда:) gc_collect_cycles() помогает, но объем используемой памяти всё равно может неуклонно расти. Поэтому проверяйте объём используемой памяти, и в случае превышения определенного лимита инициируйте перезагрузку WSS.
  • 31.
    Пример упрощенного кодаядра WSS $flag = true; While ($flag) { If (time() - $time_last_check >= 60 сек) { If (get_file_flag() == 1) { $flag = false; } else if (memory_get_peak_usage()/1024/1024 >= ini_get("memory_limit") * 0.8) { send_notice(); set_timer_to_reboot(); $flag = false(); } } }
  • 32.
    Возможности «виртуального» кэша •Так как процесс обрабатывающий сообщения один, то и сохраняя данные в определенный массив/объект можно получить нечто на подобие кэша с актуальными данными; • Следует учитывать ограничения на объём памяти и не забывать подчищать такой кэш. • Определив экспериментальным путем суточные потребности ERP системы были увеличены лимиты с 128Мб, до 1Гб памяти для WSS, тем самым все необходимые для работы данные в результате находились в кэше. • В PHP 5.3.0 можно указывать в php.ini memory_limit 1G
  • 33.
    Ссылки на ресурсы,статьи, GitHub http://en.wikipedia.org/wiki/Comet_(programming) http://en.wikipedia.org/wiki/WebSocket https://github.com/nicokaiser/php-websocket http://nginx.com/news/nginx-websockets.html https://github.com/disconnect/apache-websocket https://github.com/kakserpom/phpdaemon https://github.com/nicokaiser/php-websocket https://github.com/hoaproject/Websocket https://github.com/lemmingzshadow/php-websocket
  • 34.