Модуль Nchan веб-сервера nginx. Работа с Websocket, EventSource (Server-Sent Events), Long-Polling

    В это статье будет сделан обзор возможностей модуля Nchan веб-сервера nginx, который заменил deprecated модуль NGiNX_HTTP_Push_Module. Модуль Nchan поддерживает основные технологии отправки сообщений Websocket, EventSource (Server-Sent Events), Long-Polling. Для горизонтального масштабирования используется кластер серверов redis.

    Технология Websocket по-прежнему не на все 100% покрывается распространенными веб-браузерами см. статистику. Да, не поддерживают всего лишь 6% веб-браузеров. Однако если клиент включил в договор пункт о поддержке Opera-mini, то без fallback на Long-Polling уже не обойтись. Есть еще один момент, который снижает доступность технологии Websocket, правда статистику я не могу найти. Может быть кто-то подскажет где взять ее. Websocket могут не поддерживать некоторые системы защиты от DDoS, провайдеры в некоторых странах с законодательными ограничениями, некоторые провайдеры мобильного интернета, а также фильтроваться при доступе к интернет через корпоративный брандмауэр, если его так решили настроить системные администраторы из соображений безопасности или снижения нагрузки.

    Другая существенная проблема в технологиии Websocket является горизонтальное масштабирование. Процитирую документацию pm2 (Process Manager for node.js) из раздела Cluster Mode.
    Statelessify your application

    Be sure your application is stateless meaning that no local data is stored in the process, for example sessions/websocket connections, session-memory and related. Use Redis, Mongo or other databases to share states between processes.

    Another resource on how to write efficient, production ready stateless application is The Twelve Factor Application manifesto.
    То есть для горизонтального масштабирования (даже если например приложение node.js запускается на одном сервере, но на нескольких ядрах) необходимо использовать дополнительные механизмы для организации общей шины сообщений для всего кластера.

    И, наконец, появился новый игрок — это технология Server-Sent Events. Статистика поддержки браузерами практически такая же как и для Websocket (то есть весьма хорошая) см. статистику. А вот применение распространение как мне кажется все еще на начальном уровне (то есть никакое). Преимущество Nchan в том, что применение всех трех технологий прозрачно как для клиента так и для сервера.

    Модуль Nchan включён в сборку nginx-extras. Для удобства читателей я разместил в своём репозитарии конфигурацию для docker-compose.

    Для работы клиента есть библиотека https://github.com/slact/nchan.js. Определить с каким протоколом работать можно явно или в порядке приоритета. Поддерживаются три протокола Websocket, EventSource (Server-Sent Events), Long-Polling прозрачно для клиента и для сервера.

    var opt = {
      subscriber: 'websocket', // 'longpoll',  'eventsource', or 'websocket'
        //or an array of the above indicating subscriber type preference
      reconnect: undefined, // undefined or 'session' or 'persist'
        //if the HTML5 sessionStore or localStore should be used to resume
        //connections interrupted by a page load
      shared: undefined, // true,  or undefined
        //share connection to same subscriber url between browser
        //windows and tabs using localStorage. In shared mode,
        //only 1 running subscriber is allowed per url per window/tab.
    }
    
    var sub = new NchanSubscriber('/sub?id=mytopic', opt);
    
    sub.on("message", function(message, message_metadata) {
      console.log(message)
      console.log(message_metadata)
      // message is a string
      // message_metadata is a hash that may contain 'id' and 'content-type'
    });
    
    sub.start(); // begin (or resume) subscribing
    

    На сервере необходимо настроить url через которые будут прослушиваться и отправляться сообщения в topic.

      nchan_redis_url "redis://redis";
      nchan_storage_engine "redis";
      nchan_message_buffer_length 100;
      nchan_message_timeout 5s;
    
      location = /sub {
        nchan_subscriber;
        nchan_channel_id $arg_id;
        nchan_use_redis on;
      }
    
      location = /pub {
        nchan_publisher;
        nchan_channel_id $arg_id;
        nchan_use_redis on;
      }
    

    Для меня было небольшим удивлением что сообщения очень хорошо сохраняются сервером поэтому я настроил время хранения сообщений 5 с., чтобы при перегрузке страницы они не доставлялись одним махом начиная с первого. Значение по умолчанию 3600 с.

    Ну и наконец отправить сообщение в topic можно простым запросом POST

    curl --request POST --data "test message" http://localhost:8003/pub?id=mytopic
    

    apapacy@gmail.com
    7 мая 2018 года

    Комментарии 4

      0
      Спасибо за статью! Может подскажете есть ли такой модуль под Apache?
        0
        И ещё вопрос как его подружить с очередями сообщений или как обеспечить гарантированному доставки сообщений?
          0
          Скорее всего для apache подобного модуля нет. Есть созвучные проекты socket.io SockJS. Доставка сообщений гарантируется. Однако если присоединиться к тому же топика сообщения до ставятся повторно. Поэтому при необходимости либо нужно менять томик либо сохранять в локальном стопе идентификатор последнего доставленного сообщения чтобы пропускать лишнее
          0
          С помощью буферов сообщений?

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

          Самое читаемое