Шкарбатов Дмитрий

Руководитель департамента

разработки кассовых продуктов

WebSocket (RFC 6455) — протокол полнодуплексной связи (может передавать и принимать одновременно) поверх TCP-соединения, предназначенный для обмена сообщениями между браузером и веб-сервером в режиме реального времени.

Он позволяет пересылать любые данные, на любой домен, безопасно и почти без лишнего сетевого трафика.

WebSocket

Протокол WebSocket работает над HTTP.

Это означает, что при соединении браузер отправляет специальные заголовки, спрашивая: «поддерживает ли сервер WebSocket?».

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

Установление WebSocket соединений

Соединение WebSocket можно открывать как WS:// или как WSS://. Протокол WSS представляет собой WebSocket над HTTPS.

Кроме большей безопасности, у WSS есть важное преимущество перед обычным WS – большая вероятность соединения.

Дело в том, что HTTPS шифрует трафик от клиента к серверу, а HTTP – нет.

Если между клиентом и сервером есть прокси, то в случае с HTTP все WebSocket-заголовки и данные передаются через него. Прокси имеет к ним доступ, ведь они никак не шифруются, и может расценить происходящее как нарушение протокола HTTP, обрезать заголовки или оборвать передачу. А в случае с WSS весь трафик сразу кодируется и через прокси проходит уже в закодированном виде. Поэтому заголовки гарантированно пройдут.

WSS

В протокол встроена проверка связи при помощи управляющих фреймов типа PING и PONG.

Тот, кто хочет проверить соединение, отправляет фрейм PING с произвольным телом. Его получатель должен в разумное время ответить фреймом PONG с тем же телом.

Этот функционал встроен в браузерную реализацию, так что браузер ответит на PING сервера, но управлять им из JavaScript нельзя.

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

PING/PONG

Can I use

Как с ними работать?

// Создаем объект сокета
var socket = new WebSocket("ws://ws.privatbank.ua");

// У объекта socket есть четыре коллбэка:
// один при получении данных и три – при изменениях в состоянии соединения:

socket.onopen = function() {
  alert("Соединение установлено.");
};

socket.onclose = function(event) {
  if (event.wasClean) {
    alert('Соединение закрыто чисто');
  } else {
    alert('Обрыв соединения'); // например, "убит" процесс сервера
  }

  alert('Код: ' + event.code + ' причина: ' + event.reason);
};

socket.onmessage = function(event) {
  alert("Получены данные " + event.data);
};

socket.onerror = function(error) {
  alert("Ошибка " + error.message);
};

socket.send("Привет");

Нагрузка

Вы будете создавать коннект через сокет при каждой загрузке страницы! У вас банально закончатся все свободные коннекты.

Информация о сокетах


dmitriy@shkarbatov-PC:/srv/curex$ ss -s && ss -otp state time-wait | wc -l

Total: 2031 (kernel 2206)
TCP:   33958 (estab 868, closed 32848, orphaned 6, synrecv 0, timewait 32847/0), ports 17458

Transport Total     IP        IPv6
*         2206      -         -        
RAW       0         0         0        
UDP       142       135       7        
TCP       1110      1105      5        
INET      1252      1240      12       
FRAG      0         0         0        

33357

Оптимизация сервера

net.ipv4.tcp_tw_recycle = 1

Разрешает быструю утилизацию сокетов, находящихся в состоянии TIME-WAIT.


net.ipv4.tcp_tw_reuse = 1

Определяет возможность повторного использования сокетов TIME-WAIT для новых соединений.

 

net.netfilter.nf_conntrack_tcp_timeout_time_wait = 10

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

Зачение по умолчанию = 120 сек.

Тестирование

  • Нагрузка сервера с помощью Apache Jmeter (нужен дополнительный плагин) автоматизированная работа

 

  • Фронт, с привлечением разработчика ручная работа

Каково решение?

Серебрянной пули - нет!

Отдельный контекст для выполнения фоновых задач, который не блокирует UI. Обычно worker создаётся в виде отдельного скрипта, ресурсы worker-а живут в процессе создавшей его страницы.


В worker-е есть:

  • navigator
  • location
  • applicationCache
  • XHR, websocket
  • importScripts для синхронной загрузки скриптов

 

Но он нам не подойдет :)

Worker

То же самое, что и Worker, но может быть использован с нескольких страниц.

Shared Worker

DOM

В worker-е нельзя использовать DOM, вместо window глобальный объект называется self. Нельзя получить доступ к localStorage и рисовать на canvas.
 

Доступ к объектам

Из worker-ов нельзя вернуть объект. В javascript нет lock-ов и других возможностей потокобезопасности, поэтому из worker-ов нельзя передавать объекты по ссылке, всё отправленное в worker или из него будет скопировано.

Ограничения

CORS

Пока что worker-ы не поддерживают совместное использование ресурсов между разными источниками, создать worker можно только загрузив его со своего домена.

 

Размер стека

Для worker-ов выделяется меньший размер стека, иногда это имеет значение.

Ограничения

  • когда он закроется сам, вызвав self.close()
  • когда закроются все странички, его использующие (при этом у worker-а не будет возможности закончить вычисления)
  • когда пользователь принудительно завершит его (например, в хроме из chrome://inspect)
  • когда упадёт или он, или процесс странички, где он живёт

Завершение работы

Can I use

Debug


chrome://inspect/#workers
chrome://inspect/#service-workers

Использование


web_worker = new SharedWorker('shared_worker.js');

web_worker.port.addEventListener('message', function(e) {

     // On message receive
     if (e.data.operation === 'on_message') {
        alert('SocketOnMessage');

    // On error connection
    } else if (e.data.operation === 'on_error') {
        alert('SocketOnError');

    // On close connection, trying to reconnect in 3 sec
    } else if (e.data.operation === 'on_close') {
        alert('SocketOnClose');
    }
}, false);

// Shared Worker On Error
web_worker.onerror = function(err){
    alert('WebWorkerError ' + err.message);
    web_worker.port.close();
};

// Init SharedWorker
web_worker.port.start();

// Start command Shared Worker
web_worker.port.postMessage({'cmd': 'start', 'url': 'ws://ws.privatbank.ua'});

shared_worker.js

var port;
var ws = null;

var count = 0;
var peers = [];

self.addEventListener('connect', function(e) {

port = e.ports[0];
peers.push(port);
count += 1;

port.addEventListener('message', function(e) {

    // Start
    if (e.data.cmd === 'start') {

        if (ws === null) {
            // Socket init
            ws = new WebSocket(e.data.url);
        }

        // On message receive
        ws.onmessage = function (msg) {
            send({
                'operation': 'on_message',
                'data': JSON.parse(msg.data)
            });
        };
        // On error connection
        ws.onerror = function () {
            ws = null;
            send({'operation': 'on_error'});
        };

        // On close connection
        ws.onclose = function (event) {
            ws = null;
            send({'operation': 'on_close',
                'data': event.code});
        };

    // Send Message
    } else if (e.data.cmd === 'send') {
        if (ws !== null && ws.readyState === 1)
            ws.send(e.data.data);
    }

    // Отправляем данные клиенту
    function send (data) {
        peers.forEach(function (port) {
            port.postMessage(data);
        });
    }
}, false);

port.start();

}, false);

SharedWorker

Service workers

Service workers фактически действуют как прокси серверы, находящиеся между web-приложением и браузером. Они призваны для того, чтобы позволять описывать корректное поведение в режиме офлайн, перехватывать запросы сети и принимать соответствующие меры, основываясь на том, доступна сеть или нет, и обновлять данные, находящиеся на сервере. Так же они будут позволять отправлять уведомления и выполять фоновую синхронизацию API.

Service workers

Service workers запускаются только поверх HTTPS из соображений безопасности.

Многие функции Service Worker теперь включены по умолчанию в новых браузерах, поддерживающих эту технологию. Однако для некоторых вам может понадобиться их включить.

Can I use

Выводы

- Нет серебрянной пули

- Нет 100% поддержки браузерами

- Очень мало понятной информации

 

+ В нашем случае снижение нагрузки на 50%

+ Технология проста в освоении

+ Гибкая в использовании

   Shared Worker -> Worker -> WebSocket -> AJAX

Вопросы?

Удачи!

WebSockets

By James Jason

WebSockets

  • 948