Перейти к содержанию

nchan: Масштабируемый, гибкий сервер публикации/подписки для современного веба

Установить на Debian/Ubuntu

Эти документы применимы к пакету APT nginx-module-nchan, предоставляемому репозиторием GetPageSpeed Extras.

  1. Настройте репозиторий APT, как описано в настройке репозитория APT.
  2. Установите модуль:
sudo apt-get update
sudo apt-get install nginx-module-nchan
Показать наборы и архитектуры
| Distro   | Suite             | Component   | Architectures   |
|----------|-------------------|-------------|-----------------|
| debian   | bookworm          | main        | amd64, arm64    |
| debian   | bookworm-mainline | main        | amd64, arm64    |
| debian   | trixie            | main        | amd64, arm64    |
| debian   | trixie-mainline   | main        | amd64, arm64    |
| ubuntu   | focal             | main        | amd64, arm64    |
| ubuntu   | focal-mainline    | main        | amd64, arm64    |
| ubuntu   | jammy             | main        | amd64, arm64    |
| ubuntu   | jammy-mainline    | main        | amd64, arm64    |
| ubuntu   | noble             | main        | amd64, arm64    |
| ubuntu   | noble-mainline    | main        | amd64, arm64    |

https://nchan.io

Nchan — это масштабируемый, гибкий сервер публикации/подписки для современного веба, построенный как модуль для веб-сервера Nginx. Он может быть настроен как независимый сервер или как посредник между вашим приложением и сотнями, тысячами или миллионами живых подписчиков. Он может кэшировать сообщения в памяти, на диске или через Redis. Все подключения обрабатываются асинхронно и распределены между любым количеством рабочих процессов. Он также может масштабироваться на множество серверов Nginx с помощью Redis.

Сообщения публикуются в каналы с помощью HTTP-запросов POST или вебсокетов, и подписываются также через вебсокеты, долгосрочное опрашивание, EventSource (SSE), старомодное интервальное опрашивание, и другие.

В веб-браузере можно использовать вебсокеты или EventSource по умолчанию или библиотеку-обертку NchanSubscriber.js. Она поддерживает Долгосрочное опрашивание, EventSource и возобновляемые вебсокеты, и имеет несколько других удобных опций. Также доступна на NPM.

Возможности

Статус и история

Последний релиз Nchan — 1.3.7 (19 сентября 2024) (журнал изменений).

Первая итерация Nchan была написана в 2009-2010 годах как Модуль HTTP Push Nginx и была значительно переработана в свое текущее состояние в 2014-2016 годах.

Обновление с модуля HTTP Push Nginx

Хотя Nchan совместим с любыми директивами конфигурации модуля Push, некоторые более необычные и редко используемые настройки были отключены и будут игнорироваться (с предупреждением). Смотрите страницу обновления для получения подробного списка изменений и улучшений, а также полного списка несовместимостей.

Масштабируется ли это?

график времени ответа внутреннего подписчика

Да, масштабируется. Как Nginx, Nchan может легко обрабатывать любой трафик, который вы ему предоставите. Я пытался оценить его, но мои инструменты оценки намного медленнее, чем Nchan. Данные, которые я собрал, показывают, сколько времени Nchan нужно для того, чтобы ответить каждому подписчику после публикации сообщения — это исключает время рукопожатия TCP и внутренний парсинг HTTP-запросов. По сути, это измеряет, как Nchan масштабируется, предполагая, что все остальные компоненты уже настроены для масштабируемости. График данных — это средние значения 5 запусков с сообщениями в 50 байт.

С хорошо настроенной ОС и сетевым стеком на недорогом серверном оборудовании ожидайте способность обрабатывать более 300 000 одновременных подписчиков в секунду при минимальной загрузке CPU. Nchan также можно масштабировать на несколько экземпляров Nginx с использованием Redis, и это тоже может быть масштабировано выше одной единой точки отказа, используя Redis Cluster.

Начало работы

После того как вы соберете и установите Nchan, его очень легко начать использовать. Добавьте два местоположения в ваш конфиг nginx:

#...
http {  
  server {
    #...

    location = /sub {
      nchan_subscriber;
      nchan_channel_id $arg_id;
    }

    location = /pub {
      nchan_publisher;
      nchan_channel_id $arg_id;
    }
  }
}

Теперь вы можете публиковать сообщения в каналы, отправляя данные на /pub?id=channel_id, и подписываться, указывая вебсокет, EventSource или NchanSubscriber.js на sub/?id=channel_id. Все просто.

Но Nchan очень гибок и высоко конфигурируем. Так что, конечно, он может стать гораздо более сложным...

Концептуальный обзор

Основной единицей большинства решений для публикации/подписки является сообщение канала. Nchan не исключение. Поставщики отправляют сообщения в каналы с определенным идентификатором канала, а подписчики, подписанные на эти каналы, получают их. Некоторое количество сообщений может быть отложено на некоторое время в буфере сообщений канала, прежде чем они будут удалены. Довольно просто, не так ли?

Но... проблема в том, что конфигурация nginx не работает с каналами, поставщиками и подписчиками. Вместо этого в нем есть несколько секций для входящих запросов, которые совпадают с секциями сервера и местоположения. Указания конфигурации Nchan сопоставляют серверы и местоположения с конечными точками публикации и подписки канала:

#очень базовая конфигурация nchan
worker_processes 5;

http {  
  server {
    listen       80;

    location = /sub {
      nchan_subscriber;
      nchan_channel_id foobar;
    }

    location = /pub {
      nchan_publisher;
      nchan_channel_id foobar;
    }
  }
}

Вышее сопоставляет запросы к URI /sub с конечной точкой подписчика канала foobar, а аналогично /pub с конечной точкой поставщика канала foobar.

Конечные точки поставщика

Конечные точки поставщика — это местоположения конфигурации Nginx с директивой nchan_publisher.

Сообщения могут быть опубликованы в канал, отправляя HTTP POST запросы с содержимым сообщения в местоположения конечной точки поставщика. Вы также можете публиковать сообщения через соединение вебсокета в то же местоположение.

  location /pub {
    #пример местоположения поставщика
    nchan_publisher;
    nchan_channel_id foo;
    nchan_channel_group test;
    nchan_message_buffer_length 50;
    nchan_message_timeout 5m;
  }

Публикация сообщений

Запросы и сообщения вебсокетов будут отвечены информацией о канале в момент публикации сообщения. Вот пример отправки с помощью curl:

>  curl --request POST --data "test message" http://127.0.0.1:80/pub

 очередные сообщения: 5
 последний запрос: 18 секунд назад
 активные подписчики: 0
 последний идентификатор сообщения: 1450755280:0

Ответ может быть в текстовом формате (как выше), JSON или XML, в зависимости от заголовка Accept запроса:

> curl --request POST --data "test message" -H "Accept: text/json" http://127.0.0.2:80/pub

 {"messages": 5, "requested": 18, "subscribers": 0, "last_message_id": "1450755280:0" }

Поставщики вебсокетов также получают одинаковые ответы во время публикации, с кодировкой, определяемой заголовком Accept во время рукопожатия.

Код ответа для HTTP-запроса 202 Принято, если на момент публикации подписчиков нет, или 201 Создано, если по крайней мере один подписчик был присутствует.

Метаданные могут быть добавлены к сообщению при использовании HTTP POST запроса для публикации. Заголовок Content-Type будет связан как тип содержимого сообщения (и выводиться в Long-Poll, Interval-Poll и multipart/mixed подписчики). Заголовок X-EventSource-Event также может быть использован для связывания значения строки события event: EventSource с сообщением.

Другие действия конечных точек поставщика

HTTP GET запросы возвращают информацию о канале без публикации сообщения. Код ответа 200, если канал существует, и 404, если нет:

> curl --request POST --data "test message" http://127.0.0.2:80/pub
  ...

> curl -v --request GET -H "Accept: text/json" http://127.0.0.2:80/pub

 {"messages": 1, "requested": 7, "subscribers": 0, "last_message_id": "1450755421:0" }

HTTP DELETE запросы удаляют канал и заканчивают все соединения подписчиков. Как и запросы GET, это возвращает ответ со статусом 200 с информацией о канале, если канал существовал, и 404 в противном случае.

Как работают настройки канала

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

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

Конечные точки подписчика

Конечные точки подписчика — это места конфигурации Nginx с директивой nchan_subscriber.

Nchan поддерживает несколько различных типов подписчиков для получения сообщений: вебсокеты, EventSource (Серверные события), долгосрочные опросы, интервальные опросы. HTTP с фрагментами и HTTP multipart/mixed.

  location /sub {
    #пример местоположения подписчика
    nchan_subscriber;
    nchan_channel_id foo;
    nchan_channel_group test;
    nchan_subscriber_first_message oldest;
  }
  • Долгосрочное опрашивание

    Испытанный метод серверного пула, поддерживаемый каждым браузером.
    Инициализируется путем отправки HTTP GET запроса на конечную точку подписчика канала.
    Долгосрочный подписчик проходит через очередь сообщений канала через встроенный механизм кэширования HTTP-клиентов, а именно с заголовками "Last-Modified" и "Etag". Явно, для получения следующего сообщения для данного долгосрочного подписчика, отправьте запрос с заголовком "If-Modified-Since", установленным на заголовок "Last-Modified" предыдущего ответа, и "If-None-Match", аналогично, установленным на заголовок "Etag" предыдущего ответа.
    Отправка запроса без заголовков "If-Modified-Since" или "If-None-Match" возвращает самое старое сообщение в очереди сообщений канала или ожидает следующего опубликованного сообщения в зависимости от значения директивы конфигурации nchan_subscriber_first_message.
    Связанный тип содержимого сообщения, если он имеется, будет отправлен этому подписчику с заголовком Content-Type.

  • Интервальное опрашивание

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

  • Вебсокеты

    Двунаправленная связь для веб-браузеров. Часть спецификации HTML5. Nchan поддерживает последнюю версию протокола 13 (RFC 6455).
    Инициализируется отправкой рукопожатия вебсокета в желаемое местоположение конечной точки подписчика.
    Если соединение вебсокета закрывается сервером, фрейм close будет содержать код ответа HTTP и строку состояния, описывающую причину закрытия соединения. Автоматизированные пинги keep-alive от сервера могут быть настроены с директивой nchan_websocket_ping_interval. Сообщения доставляются подписчикам в текстовых фреймах вебсокетов, за исключением случаев, когда content-type сообщения равен "application/octet-stream" — тогда оно доставляется в бинарном фрейме.
    Подписчики вебсокетов могут использовать пользовательский подпроект ws+meta.nchan, чтобы получать метаданные сообщения вместе с сообщениями, что позволяет возобновлять соединения вебсокетов. Сообщения, полученные с помощью этого подпроекта, имеют форму

      id: message_id
      content-type: message_content_type
      \n
      message_data
      

Строка content-type: может быть опущена.
#### Поставщик вебсокетов Сообщения, опубликованные через соединение вебсокета, могут быть перенаправлены на вышестоящее приложение с помощью nchan_publisher_upstream_request директивы конфигурации.
Сообщения, опубликованные в бинарном фрейме, автоматически получают content-type "application/octet-stream". #### Сжатие сообщения Nchan версии 1.1.8 и выше поддерживает расширение протокола permessage-deflate. Сообщения сжимаются один раз при публикации, а затем могут быть распространены на любое количество совместимых подписчиков вебсокетов. Сжатие сообщения включается путем установки директивы nchan_deflate_message_for_websocket on; в местоположении поставщика.
Сжатые данные хранятся вместе с оригинальным сообщением в памяти, или, если они достаточно велики, на диске. Это означает, что больше общей памяти необходимо при использовании nchan_deflate_message_for_websocket.
Параметры сжатия (скорость, использование памяти, стратегия и т.д.) можно настроить с помощью директив nchan_permessage_deflate_compression_window, nchan_permessage_deflate_compression_level, nchan_permessage_deflate_compression_strategy, и nchan_permessage_deflate_compression_window настройки.
Nchan также поддерживает (устаревшее) расширение perframe-deflate, который все еще используется Safari как x-webkit-perframe-deflate.

  • EventSource

    Также известный как Серверные события или SSE, он предшествовал вебсокетам в спецификации HTML5 и является очень простым протоколом.
    Инициализируется отправкой HTTP GET запроса на конечную точку подписчика канала с заголовком "Accept: text/event-stream".
    Каждый сегмент сообщения data: будет предшествоваться сообщением id:.
    Чтобы возобновить закрытое соединение EventSource с последнего полученного сообщения, нужно начать соединение с заголовком "Last-Event-ID", установленным на id последнего сообщения.
    К сожалению, браузеры не поддерживают установку этого заголовка для объекта EventSource, поэтому по умолчанию последний идентификатор сообщения устанавливается либо из заголовка "Last-Event-Id", либо из аргумента строки запроса last_event_id URL.
    Это поведение можно настроить с помощью nchan_subscriber_last_message_id конфигурации.
    Связанный content-type сообщения не будет получен подписчиком EventSource, так как протокол не делает никаких положений для этих метаданных. Связанный тип event сообщения, если имеется, будет отправлен этому подписчику с линией event:.

  • HTTP multipart/mixed

    MIME-тип multipart/mixed был предусмотрен для электронной почты, но почему бы не использовать его для HTTP? Он легко парсится и включает метаданные с каждым сообщением.
    Инициализируется с добавлением заголовка Accept: multipart/mixed.
    Заголовки ответа и неиспользуемая часть "предисловия" тела ответа отправляются сразу, с контрольной строкой, сгенерированной случайным образом для каждого подписчика. Каждое последующее сообщение будет отправлено как одна часть многочастного сообщения и будет включать время сообщения и метку (Last-Modified и Etag), а также необязательные заголовки Content-Type.
    Каждое сообщение завершается контрольной строкой следующего многочастного сообщения без завершающей новой строки. Хотя это соответствует спецификации multipart, это необычно, так как многочастные сообщения определяются как начинающиеся, а не заканчивающиеся контрольной строкой.
    Связанный тип содержимого сообщения, если он имеется, будет отправлен этому подписчику с заголовком Content-Type.

  • HTTP Raw Stream

    Простой метод подписки, аналогичный потоковому подписчику Модуля HTTP Push Stream Nginx. Сообщения добавляются в тело ответа, разделенные новой строкой или настраиваемыми с помощью nchan_subscriber_http_raw_stream_separator.

  • HTTP Chunked Transfer

    Этот метод подписки использует chunked Transfer-Encoding для получения сообщений.
    Инициализируется явным добавлением chunked в заголовок TE:
    TE: chunked (или TE: chunked;q=??, где qval > 0)
    Заголовки ответа отправляются сразу, и каждое сообщение будет отправлено в индивидуальном фрагменте. Обратите внимание, что поскольку фрагмент нулевой длины завершает передачу, сообщения нулевой длины не будут отправлены подписчику.
    В отличие от других типов подписчиков, chunked подписчик не может использовать http/2, так как это запрещает кодирование фрагментами.

PubSub Endpoint

Конечные точки PubSub — это местоположения конфигурации Nginx с директивой nchan_pubsub.

Комбинация конечных точек поставщика и подписчика, это местоположение обрабатывает все HTTP GET запросы как подписчиков, а все HTTP POST как поставщиков. Каналы не могут быть удалены через конечную точку pubsub с HTTP DELETE запросом.

Одним простым примером использования является эхо-сервер:

  location = /pubsub {
    nchan_pubsub;
    nchan_channel_id foo;
    nchan_channel_group test;
  }

Более интересная настройка может устанавливать разные идентификаторы каналов для поставщика и подписчика:

  location = /pubsub {
    nchan_pubsub;
    nchan_publisher_channel_id foo;
    nchan_subscriber_channel_id bar;
    nchan_channel_group test;
  }

Здесь подписчики будут слушать сообщения на канале foo, а поставщики будут публиковать сообщения в канал bar. Это может быть полезно при настройке проксирования вебсокетов между веб-клиентами и вашим приложением.

Идентификатор канала

До сих пор в примерах использовались статические идентификаторы каналов, что не очень полезно. На практике идентификатор канала может быть установлен на любую переменную nginx, например, аргумент строки запроса, значение заголовка или часть URL местоположения:

  location = /sub_by_ip {
    #идентификатор канала - это IP-адрес подписчика
    nchan_subscriber;
    nchan_channel_id $remote_addr;
  }

  location /sub_by_querystring {
    #идентификатор канала - это параметр строки запроса chanid
    # GET /sub/sub_by_querystring?foo=bar&chanid=baz будет иметь идентификатор канала, установленный на 'baz'
    nchan_subscriber;
    nchan_channel_id $arg_chanid;
  }

  location ~ /sub/(\w+)$ {
    #идентификатор канала - это слово после /sub/
    # GET /sub/foobar_baz будет иметь идентификатор канала, установленный на 'foobar_baz'
    # Я надеюсь, вы знаете свои регулярные выражения...
    nchan_subscriber;
    nchan_channel_id $1; #первая захваченная часть сопоставления местоположения
  }

Я рекомендую использовать последний вариант, идентификатор канала, производный от URL запроса через регулярное выражение. Это делает вещи простыми и RESTful.

Мультиплексирование каналов

С мультиплексированием каналов подписчики могут подписаться на до 255 каналов за соединение. Сообщения, опубликованные во все указанные каналы, будут доставлены в порядке подписки. Существует два способа включения мультиплексирования:

До 7 идентификаторов каналов могут быть указаны для директивы конфигурации nchan_channel_id или nchan_channel_subscriber_id:

  location ~ /multisub/(\w+)/(\w+)$ {
    nchan_subscriber;
    nchan_channel_id "$1" "$2" "common_channel";
    #GET /multisub/foo/bar будет подписан на:
    # каналы 'foo', 'bar' и 'common_channel',
    #и будет получать сообщения из всех вышеперечисленных.
  }

Для более чем 7 каналов nchan_channel_id_split_delimiter можно использовать для разделения nchan_channel_id или nchan_channel_subscriber_id на до 255 отдельных идентификаторов каналов:

  location ~ /multisub-split/(.*)$ {
    nchan_subscriber;
    nchan_channel_id "$1";
    nchan_channel_id_split_delimiter ",";
    #GET /multisub-split/foo,bar,baz,a будет подписан на:
    # каналы 'foo', 'bar', 'baz' и 'a'
    #и будет получать сообщения из всех вышеперечисленных.
  }

Также возможно публиковать сообщения в несколько каналов с одним запросом, а также удалять несколько каналов с одним запросом, с аналогичной конфигурацией:

  location ~ /multipub/(\w+)/(\w+)$ {
    nchan_publisher;
    nchan_channel_id "$1" "$2" "another_channel";
    #POST /multipub/foo/bar будет публиковать в:
    # каналы 'foo', 'bar', 'another_channel'
    #DELETE /multipub/foo/bar будет удалять:
    # каналы 'foo', 'bar', 'another_channel'
  }

Когда канал удаляется, все его сообщения удаляются, и все соединения его подписчиков закрываются — включая тех, кто подписан через мультиплексированное местоположение. Например, предположим, что подписчик подписан на каналы "foo" и "bar" через одно мультиплексированное соединение. Если "foo" будет удалён, соединение закроется, и подписчик, следовательно, потеряет подписку на "bar".

Смотрите раздел Безопасность канала о том, как использовать хорошие идентификаторы и поддерживать безопасность частных каналов.

Группы каналов

Каналы могут быть ассоциированы с группами для избежания конфликтов идентификаторов каналов:

  location /test_pubsub {
    nchan_pubsub;
    nchan_channel_group "test";
    nchan_channel_id "foo";
  }

  location /pubsub {
    nchan_pubsub;
    nchan_channel_group "production";
    nchan_channel_id "foo";
    #одинаковый идентификатор канала, разная группа канала. Таким образом, разный канал.
  }

  location /flexgroup_pubsub {
    nchan_pubsub;
    nchan_channel_group $arg_group;
    nchan_channel_id "foo";
    #группу можно установить и с помощью переменных запроса
  }

Лимиты и учет

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

  #включить учет групп
  nchan_channel_group_accounting on;

  location ~ /pubsub/(\w+)$ {
    nchan_pubsub;
    nchan_channel_group "limited";
    nchan_channel_id $1;
  }

  location ~ /prelimited_pubsub/(\w+)$ {
    nchan_pubsub;
    nchan_channel_group "limited";
    nchan_channel_id $1;
    nchan_group_max_subscribers 100;
    nchan_group_max_messages_memory 50M;
  }

  location /group {
    nchan_channel_group limited;
    nchan_group_location;
    nchan_group_max_channels $arg_max_channels;
    nchan_group_max_messages $arg_max_messages;
    nchan_group_max_messages_memory $arg_max_messages_mem;
    nchan_group_max_messages_disk $arg_max_messages_disk;
    nchan_group_max_subscribers $arg_max_subs;
  }

Здесь /group является nchan_group_location, который используется для доступа и изменения данных группы. Чтобы получить данные группы, отправьте GET запрос к nchan_group_location:

>  curl http://localhost/group

каналы: 10
подписчики: 0
сообщения: 219
используемая общая память для сообщений: 42362 байт
используемое дисковое пространство для сообщений: 0 байт
лимиты:
  максимальные каналы: 0
  максимальные подписчики: 0
  максимальные сообщения: 0
  максимальное количество сообщений общая память: 0
  максимальное количество сообщений дискового пространства: 0  

По умолчанию, данные возвращаются в читаемом виде, но также могут быть отформатированы как JSON, XML или YAML:

>  curl -H "Accept: text/json" http://localhost/group

{
  "channels": 21,
  "subscribers": 40,
  "messages": 53,
  "messages_memory": 19941,
  "messages_disk": 0,
  "limits": {
    "channels": 0,
    "subscribers": 0,
    "messages": 0,
    "messages_memory": 0,
    "messages_disk": 0
  }
}

Данные в ответе относятся только к одному экземпляру Nchan, независимо от того, используется ли Redis. Лимит 0 означает 'неограниченно'.

Лимиты могут быть установлены на уровне местоположения, как в вышеупомянутом местоположении /prelimited_pubsub/..., или с помощью POST запроса к nchan_group_location:

>  curl -X POST "http://localhost/group?max_channels=15&max_subs=1000&max_messages_disk=0.5G"

каналы: 0
подписчики: 0
сообщения: 0
используемая общая память для сообщений: 0 байт
используемое дисковое пространство для сообщений: 0 байт
лимиты:
  максимальные каналы: 15
  максимальные подписчики: 1000
  максимальные сообщения: 0
  максимальное количество сообщений общая память: 0
  максимальное количество сообщений дискового пространства: 536870912

Лимиты применяются локально, независимо от того, включен ли Redis. Если запрос поставщика или подписчика превышает лимит группы, Nchan ответит на него с ответом 403 Forbidden.

Хуки и обратные вызовы

Авторизация запроса

Эта функция, настраиваемая с помощью nchan_authorize_request, ведет себя так же, как модуль http_auth_request Nginx.

Рассмотрим конфигурацию:

  upstream my_app {
    server 127.0.0.1:8080;
  }
  location = /auth {
    proxy_pass http://my_app/pubsub_authorize;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Subscriber-Type $nchan_subscriber_type;
    proxy_set_header X-Publisher-Type $nchan_publisher_type;
    proxy_set_header X-Prev-Message-Id $nchan_prev_message_id;
    proxy_set_header X-Channel-Id $nchan_channel_id;
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Forwarded-For $remote_addr;
  }

  location ~ /pubsub/auth/(\w+)$ {
    nchan_channel_id $1;
    nchan_authorize_request /auth;
    nchan_pubsub;
    nchan_channel_group test;
  }

Здесь любой запрос к местоположению /pubsub/auth/<...> должен быть авторизован вашим приложением (my_app). Nginx создаст запрос GET /pubsub_authorize к приложению, с дополнительными заголовками, установленными директивами proxy_set_header. Обратите внимание, что переменные, специфические для Nchan, доступны для этого запроса авторизации. Как только ваше приложение получит этот запрос, оно должно решить, авторизовать его или нет. Это можно сделать на основе переданной сессионной куки, IP-адреса или любых наборов параметров по вашему выбору. Если авторизован, оно должно ответить пустым ответом 200 OK.
Все коды ответов, не начинающиеся с 2xx (такие как 403 Forbidden), интерпретируются как неудачи авторизации. В этом случае неудавшийся ответ будет проксифицирован к клиенту.

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

Присутствие подписчиков

Подписчики могут уведомлять приложение, когда они подписались и отписались от канала, используя nchan_subscribe_request и nchan_unsubscribe_request настройки. Эти должны указывать на местоположения Nginx, настроенные для перенаправления запросов на прокси (ваше приложение):

  location ~ /sub/(\w+)$ {
    nchan_channel_id $1;
    nchan_subscribe_request /upstream/sub;
    nchan_unsubscribe_request /upstream/unsub;
    nchan_subscriber;
    nchan_channel_group test;
  }

  location = /upstream/unsub {
    proxy_pass http://127.0.0.1:9292/unsub;
    proxy_ignore_client_abort on;  #!!!важно!!!!
    proxy_set_header X-Subscriber-Type $nchan_subscriber_type;
    proxy_set_header X-Channel-Id $nchan_channel_id;
    proxy_set_header X-Original-URI $request_uri;
  } 
  location = /upstream/sub {
    proxy_pass http://127.0.0.1:9292/sub;
    proxy_set_header X-Subscriber-Type $nchan_subscriber_type;
    proxy_set_header X-Message-Id $nchan_message_id;
    proxy_set_header X-Channel-Id $nchan_channel_id;
    proxy_set_header X-Original-URI $request_uri;
  } 

Для корректной работы nchan_unsubscribe_request местоположение, на которое оно указывает, должно иметь proxy_ignore_client_abort on;. В противном случае внезапно прерванные подписчики могут не запустить запрос на отписку.

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

Перенаправление сообщений

Сообщения могут быть перенаправлены в вышестоящее приложение перед публикацией, используя настройку nchan_publisher_upstream_request:

  location ~ /pub/(\w+)$ {
    #конечная точка поставщика
    nchan_channel_id $1;
    nchan_pubsub;
    nchan_publisher_upstream_request /upstream_pub;
  }

  location = /upstream_pub {
    proxy_pass http://127.0.0.1:9292/pub;
    proxy_set_header X-Publisher-Type $nchan_publisher_type;
    proxy_set_header X-Prev-Message-Id $nchan_prev_message_id;
    proxy_set_header X-Channel-Id $nchan_channel_id;
    proxy_set_header X-Original-URI $request_uri;
  } 
С этой конфигурацией входящие сообщения сначала отправляются в POST запрос к http://127.0.0.1:9292/pub. Код ответа вышестоящего сервера определяет, как будет продолжаться публикация: - 304 Not Modified публикует сообщение как есть, без модификации. - 204 No Content отбрасывает сообщение. - 200 OK используется для изменения сообщения. Вместо оригинального входящего сообщения публикуется сообщение, содержащееся в этом HTTP-ответе.

Существует два основных случая использования nchan_publisher_upstream_request: перенаправление входящих данных от поставщиков вебсокетов в приложение и изменение входящих сообщений.

Хранение

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

Хранение в памяти

Этот метод хранения по умолчанию использует сегмент общей памяти для хранения сообщений и данных канала. Большие сообщения, определяемые слоем кэширования Nginx, хранятся на диске. Размер сегмента памяти настраивается с помощью nchan_shared_memory_size. Данные, хранящиеся здесь, не являются постоянными и теряются, если Nginx перезапускается или перезагружается.

Redis

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

Подключение к серверу Redis

Для подключения к одному главному серверу Redis используйте upstream с настройками nchan_redis_server и nchan_redis_pass:

http {
  upstream my_redis_server {
    nchan_redis_server 127.0.0.1;
  }
  server {
    listen 80;

    location ~ /redis_sub/(\w+)$ {
      nchan_subscriber;
      nchan_channel_id $1;
      nchan_redis_pass my_redis_server;
    }
    location ~ /redis_pub/(\w+)$ {
      nchan_redis_pass my_redis_server;
      nchan_publisher;
      nchan_channel_id $1;
    }
  }
} 

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

Каналы, не использующие Redis, могут настраиваться рядом с каналами на базе Redis, при условии, что конечные точки никогда не пересекаются. (Это можно обеспечить, как вышеупомянуто, установив отдельные nchan_channel_group.) Разные местоположения также могут подключаться к разным серверам Redis.

Nchan может работать с одним главным Redis. Он также может автоматически обнаруживать и использовать слуги Redis для балансировки трафика PUBSUB.

Redis Cluster

Nchan также поддерживает использование Redis Cluster, который добавляет масштабируемость путем шардирования каналов между узлами кластера. Кластер Redis также обеспечивает автоматическое переключение и высокую доступность, устраняя единую точку отказа одного общего сервера Redis. Он настраивается и используется следующим образом:

http {
  upstream redis_cluster {
    nchan_redis_server redis://127.0.0.1:7000;
    nchan_redis_server redis://127.0.0.1:7001;
    nchan_redis_server redis://127.0.0.1:7002;
    # вам не нужно указывать все узлы, они будут автоматически обнаружены
    # однако рекомендуется указать как минимум несколько основных узлов.
  }
  server {
    listen 80;

    location ~ /sub/(\w+)$ {
      nchan_subscriber;
      nchan_channel_id $1;
      nchan_redis_pass redis_cluster;
    }
    location ~ /pub/(\w+)$ {
      nchan_publisher;
      nchan_channel_id $1;
      nchan_redis_pass redis_cluster;
    }
  }
} 
Высокая доступность

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

Все серверы Nchan, имеющие общий сервер или кластер Redis, должны синхронизировать свои временные метки (через ntpd или ваш любимый демон ntp). Невыполнение этого может привести к пропуску или дубликату сообщений.

Восстановление после сбоя

Начиная с версии 1.3.0, Nchan попытается восстановиться после сбоев узлов кластера, ошибок ключей и изменений эпох кластера без отключения от всего кластера. Он будет пытаться сделать это, пока не будет превышено nchan_redis_cluster_max_failing_time. Кроме того, задержки попыток восстановления имеют настраиваемую дребезг, экспоненциальное увеличение и максимальные значения.

Безопасное использование Redis

Сервера Redis могут подключаться через TLS, используя настройку nchan_redis_ssl в блоке upstream, или используя схему rediss:// для URL серверов.

Пароль и необязательное имя пользователя для команды AUTH могут устанавливать настройки nchan_redis_username и nchan_redis_password в блоке upstream, или используя схему URL сервера redis://<username>:<password>@hostname.

Обратите внимание, что автоматически обнаруженные узлы Redis унаследуют настройки их родительских SSL, имени пользователя и пароля.

Настройки и оптимизации

Начиная с версии 1.2.0, Nchan использует слуг Redis для балансировки трафика PUBSUB. По умолчанию существует равная вероятность, что подписка канала PUBSUB будет направлена к любому основному или вспомогательному узлу. Директива nchan_redis_subscribe_weights доступна для тонкой настройки этой балансировки нагрузки.

Также начиная с версии 1.2.0, для предпочтения оптимизации слуг Redis для CPU или пропускной способности можно использовать nchan_redis_optimize_target. Для тяжелых нагрузок по публикации торговля составляет примерно 35% пропускной способности репликации на слуги к 30% загрузки CPU на слугах.

Статистика производительности

Статистика команд Redis была добавлена в версии 1.3.5. Они предоставляют общее количество раз, когда были выполнены разные команды Redis, и общее время, которое они заняли. Статистика относятся к конкретному серверу Nchan, не ко всем серверам, подключённым к Redis upstream. Они группируются по каждому upstream и суммируются по узлу.

http {
  upstream my_redis_cluster {
    nchan_redis_server 127.0.0.1;
  }

  server {
    #[...]

    location ~ /nchan_redis_cluster_stats$ {
      nchan_redis_upstream_stats my_redis_cluster;
    }
  }

Чтобы получить статистику, отправьте GET-запрос на статистическое местоположение.

  curl http://localhost/nchan_redis_cluster_stats

Ответ имеет вид JSON следующей формы:

{
  "upstream": "redis_cluster",
  "nodes": [
    {
      "address"        : "127.0.0.1:7000",
      "id"             : "f13d71b1d14d8bf92b72cebee61421294e95dc72",
      "command_totals" : {
        "connect"    : {
          "msec"     : 357,
          "times"    : 5
        },
        "pubsub_subscribe": {
          "msec"     : 749,
          "times"    : 37
        },
        "pubsub_unsubsribe": {
          "msec"     : 332,
          "times"    : 37
        }
        /*[...]*/
      }
    },
    {
      "address"        : "127.0.0.1:7001",
      "id"             : "b768ecb4152912bed6dc927e8f70284191a79ed7",
      "command_totals" : {
        "connect"    : {
          "msec"     : 4281,
          "times"    : 5
        },
        "pubsub_subscribe": {
          "msec"     : 309,
          "times"    : 33
        },
        "pubsub_unsubsribe": {
          "msec"     : 307,
          "times"    : 30
        },
        /*[...]*/
      },
    }
    /*[...]*/
  ]
}

В целях краткости вся хэш-таблица command_totals опущена в этой документации.

Интроспекция

Существует несколько способов узнать, что происходит внутри Nchan. Это полезно для отладки интеграции приложений и измерения производительности.

События канала

События канала — это сообщения, автоматически публикуемые Nchan, когда возникают определенные события в канале. Они очень полезны для отладки использования каналов. Тем не менее, они несут значительные затраты на производительность и должны использоваться во время разработки, а не в производстве.

События канала публикуются в специальные «мета» каналы, связанные с обычными каналами. Вот как их настроить:

location ~ /pubsub/(.+)$ {
  nchan_pubsub;
  nchan_channel_id $1;
  nchan_channel_events_channel_id $1; #включает события канала для этого местоположения
}

location ~ /channel_events/(.+) {
  #местоположение подписчика событий канала
  nchan_subscriber;
  nchan_channel_group meta; #"meta" - это ОСОБАЯ группа каналов
  nchan_channel_id $1;
}

Обратите внимание, что местоположение /channel_events/... имеет особую nchan_channel_group, meta. Эта группа зарезервирована для доступа к «каналам событий канала» или «метаканалам».

Теперь, скажем, я подписываюсь на /channel_events/foo, я буду называть это подписчиком событий канала.

Давайте посмотрим, что получает этот подписчик событий канала, когда я публикую сообщения в

Подписка на /pubsub/foo производит событие канала

subscriber_enqueue foo

Публикация сообщения на /pubsub/foo:

channel_publish foo

Отписка от /pubsub/foo:

subscriber_dequeue foo

Удаление /pubsub/foo (с помощью HTTP DELETE /pubsub/foo):

channel_delete foo

Строка события сама настраивается с помощью nchan_channel_event_string. По умолчанию она установлена на $nchan_channel_event $nchan_channel_id. Эта строка может использовать любые Nginx и переменные Nchan.

Статистика nchan_stub_status

Как и в модуле stub_status Nginx, nchan_stub_status используется для получения метрик производительности.

  location /nchan_stub_status {
    nchan_stub_status;
  }

Отправка GET-запроса на это местоположение производит ответ:

total published messages: 1906
stored messages: 1249
shared memory used: 1824K
channels: 80
subscribers: 90
redis pending commands: 0
redis connected servers: 0
redis unhealthy upstreams: 0
total redis commands sent: 0
total interprocess alerts received: 1059634
interprocess alerts in transit: 0
interprocess queued alerts: 0
total interprocess send delay: 0
total interprocess receive delay: 0
nchan version: 1.1.5

Вот что означает каждая строка и как ее интерпретировать: - total published messages: Количество сообщений, опубликованных во все каналы через этот сервер Nchan. - stored messages: Количество сообщений, в настоящее время буферизующихся в памяти. - shared memory used: Общая выделенная память, используемая для буферизации сообщений, хранения информации о каналах и других целей. Это значение должно быть с комфортом ниже nchan_shared_memory_size. - channels: Количество каналов, присутствующих на этом сервере Nchan. - subscribers: Количество подписчиков ко всем каналам на этом сервере Nchan. - redis pending commands: Количество команд, отправленных в Redis, которые ожидают ответа. Может возрасти во время повышенной нагрузки, особенно если сервер Redis перегружен. Должно иметь тенденцию к 0. - redis connected servers: Количество серверов Redis, к которым в настоящее время подключён Nchan. - redis unhealthy upstreams: Количество неработающих upstream-серверов Redis (индивидуального сервера или режим кластера), которые в настоящее время не могут использоваться для публикации и подписки. - total redis commands sent: Общее количество команд, которые этот экземпляр Nchan отправил в Redis. - total interprocess alerts received: Количество пакетов межпроцессной коммуникации, переданных между процессами рабочих процессов Nginx для Nchan. Может расти до 100-10000 в секунду при высокой нагрузке. - interprocess alerts in transit: Количество пакетов межпроцессной коммуникации, находящихся в ожидании между рабочими процессами Nginx. Может быть ненулевым во время высокой нагрузки, но со временем всегда должно стремиться к 0. - interprocess queued alerts: Количество пакетов межпроцессной коммуникации, ожидающих отправки. Может быть ненулевым во время высокой нагрузки, но со временем всегда должно стремиться к 0. - total interprocess send delay: Общее время, проведенное пакетами межпроцессной коммуникации в ожидании, если они задержаны. Может увеличиваться во время высокой нагрузки. - total interprocess receive delay: Общее время, проведенное пакетами межпроцессной коммуникации в ожидании, если они задержаны. Может увеличиваться во время высокой нагрузки. - nchan_version: текущая версия Nchan. Доступно для версии 1.1.5 и выше.

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

Безопасность каналов

Обеспечение безопасности конечных точек поставщиков

Рассмотрим случай использования приложения, где аутентифицированные пользователи каждый используют частный, выделенный канал для получения обновлений в реальном времени. Конфигурация может выглядеть следующим образом:

http {
  server {
    #доступно только на localhost
    listen  127.0.0.1:8080;
    location ~ /pub/(\w+)$ {
      nchan_publisher;
      nchan_channel_group my_app_group;
      nchan_channel_id $1;
    }
  }

  server {
    #доступно для всего мира
    listen 80;

    location ~ /sub/(\w+)$ {
      nchan_subscriber;
      nchan_channel_group my_app_group;
      nchan_channel_id $1;
    }
  }
}

Здесь конечная точка подписчика доступна на общедоступном порту 80, а конечная точка поставщика доступна только на localhost, поэтому доступ к ней могут получить только приложения, находящиеся на этом компьютере. Другой способ ограничить доступ к конечной точке поставщика — использовать настройки разрешения/запрета:

  server {
    #доступно для всего мира
    listen 80; 
    location ~ /pub/(\w+)$ {
      allow 127.0.0.1;
      deny all;
      nchan_publisher;
      nchan_channel_group my_app_group;
      nchan_channel_id $1;
    }

Здесь только локальный IP 127.0.0.1 разрешается использовать местоположение поставщика, даже если оно определено в блоке сервера, не относящемся к localhost.

Сохранение канала в тайне

Идентификатор канала, который министр должен быть конфиденциальным, следует рассматривать с такой же осторожностью, как и токен идентификатора сессии. Учитывая вышеприведенный случай использования одного канала на пользователя, как мы можем гарантировать, что только аутентифицированный пользователь и никто другой сможет получить доступ к своему каналу?

Во-первых, если вы собираетесь обеспечить безопасность содержимого канала, вы должны использовать TLS/SSL:

http {
  server {
    #доступно только на localhost
    listen  127.0.0.1:8080;
    #...конфигурация конечной точки поставщика
  }
  server {
    #доступно для всего мира
    listen 443 ssl;
    #конфигурация SSL идет здесь
    location ~ /sub/(\w+)$ {
      nchan_subscriber;
      nchan_channel_group my_app_group;
      nchan_channel_id $1;
    }
  }
}

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

Вы также должны следить за тем, чтобы сделать хотя бы одно из следующего: - Создайте хорошие, высокоэнтропийные идентификаторы канала. - Авторизовать всех подписчиков с помощью директивы конфигурации nchan_authorize_request. - Авторизовать подписчиков и скрыть идентификаторы каналов с помощью механизма "X-Accel-Redirect".

Хорошие идентификаторы

Идентификатор, который можно угадать — это идентификатор, который можно перехватить. Если вы не аутентифицируете подписчиков (как описано ниже), идентификатор канала должен быть невозможен для угадывания. Используйте как минимум 128 бит энтропии для генерации случайного токена, связанного с аутентифицированным пользователем, и делитесь им только с клиентом пользователя. Не повторно используйте токены, так же как вы бы не повторно использовали идентификаторы сессий.

X-Accel-Redirect

Эта функция использует возможность X-Accel прокси Nginx для выполнения внутреннего запроса к конечной точке подписчика. Это позволяет клиенту подписчика аутентифицироваться вашим приложением и затем перенаправляться nginx в внутреннее местоположение, выбранное вашим приложением (например, к конечной точке поставщика или подписчика). Это делает возможным наличие безопасно аутентифицированных клиентов, не знающих идентификатор канала, на который они подписаны.

Рассмотрим следующую конфигурацию:

upstream upstream_app {
  server 127.0.0.1:8080;
}

server {
  listen 80; 

  location = /sub_upstream {
    proxy_pass http://upstream_app/subscriber_x_accel_redirect;
    proxy_set_header X-Forwarded-For $remote_addr;
  }

  location ~ /sub/internal/(\w+)$ {
    internal; #это местоположение доступно только для внутренних перенаправлений nginx
    nchan_subscriber;
    nchan_channel_id $1;
    nchan_channel_group test;
  }
}

Как указано в комментарии, /sub/internal/ недоступно снаружи:

> curl  -v  http://127.0.0.1/sub/internal/foo

  < HTTP/1.1 404 Not Found
  < Server: nginx/1.9.5
  <
  <html>
  <head><title>404 Not Found</title></head>
  <body bgcolor="white">
  <center><h1>404 Not Found</h1></center>
  <hr><center>nginx/1.9.5</center>
  </body>
  </html>

Но если запрос сделан к /sub_upstream, он перенаправляется вашему приложению (my_app) на порт 8080 с URL /subscriber_x_accel_redirect. Обратите внимание, что вы можете установить любые заголовки в запросе здесь, как и в любом документации прокси_pass местоположений Nginx, но в отличие от случая с nchan_authorize_request, переменные, специфические для Nchan, не доступны.

Теперь ваше приложение должно быть настроено для обработки запроса к /subscriber_x_accel_redirect. Вы должны убедиться, что клиент должным образом аутентифицирован (возможно, используя сессионную куку), и сгенерировать связанный идентификатор канала. Если аутентификация не удалась, ответьте обычным ответом 403 Forbidden. Вы также можете передать дополнительную информацию о сбое в теле и заголовках ответа.

Если ваше приложение успешно аутентифицирует запрос подписчика, теперь вам нужно указать Nginx выполнить внутреннее перенаправление к /sub/internal/my_channel_id. Это выполняется с помощью ответа без содержимого 200 OK, который включает в себя два заголовка: - X-Accel-Redirect: /sub/internal/my_channel_id - X-Accel-Buffering: no

При наличии этих заголовков Nginx не перенаправит ответ вашего приложения клиенту и вместо этого внутренне перенаправит на /sub/internal/my_channel_id. Это будет вести себя так, как будто клиент запрашивал местоположение конечной точки подписчика напрямую.

Таким образом, используя X-Accel-Redirect, можно как аутентифицировать всех подписчиков, так и полностью скрывать идентификаторы каналов от подписчиков.

Этот метод особенно полезен для подписчиков EventSource и вебсокетов. Подписчикам долговременного опроса, возможно, потребуется повторная аутентификация для каждого нового сообщения, что может затопить ваше приложение слишком большим количеством запросов на аутентификацию.

Отзыв авторизации канала

В некоторых случаях вы можете захотеть отозвать авторизацию конкретного подписчика для данного канала (например, если разрешения пользователя изменяются). Если канал уникален для подписчика, это просто достигается удалением канала. То же самое можно сделать для совместных каналов, подписывая каждого подписчика на совместный канал и на канал, специфичный для подписчика, через мультиплексированное соединение. Удаление специального канала подписчика завершит соединение подписчика, тем самым также завершив их подписку на совместный канал. Рассмотрим следующую конфигурацию:

location ~ /sub/(\w+) {
  nchan_subscriber;
  nchan_channel_id shared_$1 user_$arg_userid;
  nchan_authorize_request /authorize;
}

location /pub/user {
  nchan_publisher;
  nchan_channel_id user_$arg_userid;
}

Запрос к /sub/foo?userid=1234 будет подписан на каналы "shared_foo" и "user_1234" через мультиплексированное соединение. Если позже вы отправите запрос DELETE к /pub/user?userid=1234, этот подписчик будет отключен и, следовательно, отписан и от "user_1234", и от "shared_foo".

Переменные

Nchan делает несколько переменных доступными в конфигурационном файле:

  • $nchan_channel_id
    Идентификатор канала, извлеченный из запроса местоположения поставщика или подписчика. Для мультиплексированных местоположений это первый идентификатор канала в списке.

  • $nchan_channel_id1, $nchan_channel_id2, $nchan_channel_id3, $nchan_channel_id4
    Как выше, но для n-го идентификатора канала в мультиплексированных каналах.

  • $nchan_subscriber_type
    Для местоположений подписчиков эта переменная устанавливается в тип подписчика (вебсокет, долгосрочный опрос и т.д.).

  • $nchan_channel_subscriber_last_seen
    Для местоположений поставщика эта переменная устанавливается в временную метку для последнего подключенного подписчика.

  • $nchan_channel_subscriber_count
    Для местоположений поставщика эта переменная устанавливается в количество подписчиков в опубликованном канале.

  • $nchan_channel_message_count
    Для местоположений поставщика эта переменная устанавливается в количество сообщений, находящихся в буфере в опубликованном канале.

  • $nchan_publisher_type
    Для местоположений поставщика эта переменная устанавливается в тип подписчика (http или вебсокет).

  • $nchan_prev_message_id, $nchan_message_id
    Текущий и предыдущий (если применимо) идентификаторы сообщений для запроса поставщика или ответа подписчика.

  • $nchan_channel_event
    Для событий канала это имя события. Полезно при настройке nchan_channel_event_string.

  • $nchan_version
    Текущая версия Nchan. Доступно с версии 1.1.5.

Кроме того, данные nchan_stub_status также доступны в виде переменных. Они доступны только в том случае, если nchan_stub_status включен хотя бы в одном местоположении:

  • $nchan_stub_status_total_published_messages
  • $nchan_stub_status_stored_messages
  • $nchan_stub_status_shared_memory_used
  • $nchan_stub_status_channels
  • $nchan_stub_status_subscribers
  • $nchan_stub_status_redis_pending_commands
  • $nchan_stub_status_redis_connected_servers
  • $nchan_stub_status_redis_unhealthy_upstreams
  • $nchan_stub_status_total_ipc_alerts_received
  • $nchan_stub_status_ipc_queued_alerts
  • $nchan_stub_status_total_ipc_send_delay
  • $nchan_stub_status_total_ipc_receive_delay

Директивы конфигурации

  • nchan_channel_id
    аргументы: 1 - 7
    по умолчанию: (none)
    контекст: server, location, if

    Идентификатор канала для местоположения поставщика или подписчика. Может иметь до 4 значений для подписки на до 4 каналов.
    более подробная информация

  • nchan_channel_id_split_delimiter
    аргументы: 1
    по умолчанию: (none)
    контекст: server, location, if

    Разделите идентификатор канала на несколько идентификаторов для мультиплексирования, используя предоставленную строку-разделитель.
    более подробная информация

  • nchan_deflate_message_for_websocket [ on | off ]
    аргументы: 1
    по умолчанию: off
    контекст: server, location

    Хранить сжатую (сдутую) копию сообщения вместе с оригинальным, чтобы отправить клиентам вебсокетов, поддерживающим расширение протокола permessage-deflate

  • nchan_eventsource_event
    аргументы: 1
    по умолчанию: (none)
    контекст: server, location, if

    Установите строку event: EventSource на это значение. Когда используется в местоположении поставщика, переопределяет заголовок X-EventSource-Event опубликованного сообщения и ассоциирует сообщение с данным значением. Когда используется в местоположении подписчика, переопределяет ассоциированную строку event: для всех сообщений данным значением.

  • nchan_eventsource_ping_comment
    аргументы: 1
    по умолчанию: (empty)
    контекст: server, location, if

    Установите комментарий EventSource : ... для периодических пингов с сервера на клиент. Новые строки не допускаются. Если пусто, никаких комментариев не отправляется с пингом.

  • nchan_eventsource_ping_data
    аргументы: 1
    по умолчанию: (empty)
    контекст: server, location, if

    Установите строку data: EventSource для периодических пингов с сервера на клиент. Новые строки не допускаются. Если пусто, никаких данных не отправляется с пингом.

  • nchan_eventsource_ping_event
    аргументы: 1
    по умолчанию: ping
    контекст: server, location, if

    Установите строку event: EventSource для периодических пингов с сервера на клиент. Новые строки не допускаются. Если пусто, тип события не отправляется с пингом.

  • nchan_eventsource_ping_interval <number> (seconds)
    аргументы: 1
    по умолчанию: 0 (none)
    контекст: server, location, if

    Интервал отправки пинг-сообщений подписчикам EventSource. Отключено по умолчанию.

  • nchan_longpoll_multipart_response [ off | on | raw ]
    аргументы: 1
    по умолчанию: off
    контекст: server, location, if

    Когда установлено в 'on', включает отправку нескольких сообщений в одном ответе долгосрочного опрашивания, разделенных с использованием схемы типа содержимого multipart/mixed. Если в ответ на запрос долгосрочного опрашивания доступно только одно сообщение, оно отправляется без изменений. Это полезно для соединений долгосрочного опрашивания с высокой задержкой, как способ минимизировать количество поездок к серверу. Когда установлено в 'raw', отправляет несколько сообщений, используя разделитель сообщения в http-raw-stream.

  • nchan_permessage_deflate_compression_level [ 0-9 ]
    аргументы: 1
    по умолчанию: 6
    контекст: http

    Уровень сжатия для алгоритма deflate, используемого в расширении permessage-deflate вебсокетов. 0: без сжатия, 1: самый быстрый, худший, 9: самый медленный, лучший

  • nchan_permessage_deflate_compression_memlevel [ 1-9 ]
    аргументы: 1
    по умолчанию: 8
    контекст: http

    Уровень памяти для алгоритма deflate, используемого в расширении permessage-deflate вебсокетов. Сколько памяти должно быть выделено для внутреннего состояния сжатия. 1 - минимальная память, медленно и снижает коэффициент сжатия; 9 - максимальная память для оптимальной скорости

  • nchan_permessage_deflate_compression_strategy [ default | filtered | huffman-only | rle | fixed ]
    аргументы: 1
    по умолчанию: default
    контекст: http

    Стратегия сжатия для алгоритма deflate, используемого в расширении permessage-deflate вебсокетов. Используйте 'default' для обычных данных, для подробностей см. раздел zlib о стратегиях сжатия

  • nchan_permessage_deflate_compression_window [ 9-15 ]
    аргументы: 1
    по умолчанию: 10
    контекст: http

    Окно сжатия для алгоритма deflate, используемого в расширении permessage-deflate вебсокетов. Базовый двоичный логарифм размера окна (размер буфера истории). Чем больше окно, тем лучше сжатие, но тем больше памяти использует компрессор.

  • **nchan_p