Краткий обзор существующих решений
Что такое web sockets
обеспечение работы web sockets на стороне сервера
основной механизм работы с web sockets в PHP
Нюансы использования
2. Актуальность данных
• Данные на странице — устаревают;
• основании устаревших данных можно принять не верное
решение;
• Не верное решение ведёт в конечном счёте к финансовым
потерям, если это приложение решает бизнес задачи.
• Выход? Нужно получать данные от сервера в момент их
поступления на сервер;
• Нужно иметь возможность инициировать отправку данных
сервером.
3. Как быть, каким способом
актуализировать данные?
• Первый тривиальный способ — запрашивать каждые n секунд
сервер о новых данных.
При этом чем чаще — тем быстрее получаем обновление
данных.
• Простой подсчёт показывает: в ERP системе за сутки будет
генерировать 2,5 миллиона запросов. КПД от работы системы —
стремится к нулю.
4. Ограничения:
согласно спецификации HTTP 1.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 с long polling
Браузер делает Ajax запрос на сервер, который остается
открытым, пока сервер не отправит данные. По таймауту
пересоздается соединение.
10. Script tag long polling
Подгружается динамически 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>
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
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);
}
}
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 —
подготовленные для
каждого типа страниц
сообщения, включающие
все специфические
данные. Не достающие
данные добираются из БД.
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