nchan: Масштабируемый, гибкий сервер pub/sub для современного веба
Установка
Вы можете установить этот модуль в любой дистрибутив на базе RHEL, включая, но не ограничиваясь:
- RedHat Enterprise Linux 7, 8, 9 и 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 и Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-nchan
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-nchan
Включите модуль, добавив следующее в начало файла /etc/nginx/nginx.conf:
load_module modules/ngx_nchan_module.so;
Этот документ описывает nginx-module-nchan v1.3.7, выпущенный 20 сентября 2024 года.

Nchan — это масштабируемый, гибкий сервер pub/sub для современного веба, построенный как модуль для веб-сервера Nginx. Его можно настроить как самостоятельный сервер или как промежуточный слой между вашим приложением и сотнями, тысячами или миллионами активных подписчиков. Он может буферизовать сообщения в памяти, на диске или через Redis. Все соединения обрабатываются асинхронно и распределяются между любым количеством рабочих процессов. Он также может масштабироваться до множества серверов Nginx с использованием Redis.
Сообщения публикуются в каналы с помощью HTTP POST запросов или Websocket, и подписываются также через Websocket, долгосрочное опрос, EventSource (SSE), старомодное интервальное опрос, и другие.
В веб-браузере вы можете использовать Websocket или EventSource нативно или библиотеку-обертку NchanSubscriber.js. Она поддерживает долгосрочное опрос, EventSource и возобновляемые Websockets, а также имеет несколько других удобных опций. Она также доступна на NPM.
Особенности
- RESTful, HTTP-нативный API.
- Поддерживает Websocket, EventSource (События, отправляемые сервером), Долгосрочное опрос и других подписчиков на основе HTTP.
- Конфигурируемые буферы сообщений на канал с гарантией доставки сообщений без повторений и потерь.
- Подписка на сотни каналов через одно соединение подписчика.
- HTTP запросы обратные вызовы и хуки для легкой интеграции.
- Интроспекция с помощью событий канала и URL для мониторинга статистики производительности.
- Учет использования групп каналов и лимиты на них.
- Быстрое, неблокирующее локальное хранилище сообщений в общей памяти и необязательное, более медленное, постоянное хранилище с использованием Redis.
- Горизонтально масштабируемый (с использованием Redis).
- Автоотказ и высокая доступность без единой точки отказа с использованием Redis Cluster.
Масштабируется ли это?

Да, масштабируется. Как и Nginx, Nchan может легко обрабатывать столько трафика, сколько вы можете ему предоставить. Я пытался провести тестирование производительности, но мои инструменты тестирования значительно медленнее, чем Nchan. Собранные данные показывают, сколько времени Nchan тратит на ответ каждому подписчику после публикации сообщения — это исключает время рукопожатия TCP и внутренний парсинг HTTP-запросов. По сути, это измеряет, как Nchan масштабируется, предполагая, что все остальные компоненты уже настроены на масштабируемость. График данных — это средние значения 5 запусков с сообщениями по 50 байт.
С хорошо настроенной ОС и сетевым стеком на стандартном серверном оборудовании ожидайте обработки более 300K одновременных подписчиков в секунду при минимальной загрузке ЦП. Nchan также может быть масштабирован на несколько экземпляров Nginx с использованием Redis storage engine, и это также может быть масштабировано выше единой точки отказа с использованием 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, и подписываться, указывая Websocket, EventSource или NchanSubscriber.js на sub/?id=channel_id. Это так просто.
Но Nchan очень гибок и высоко конфигурируем. Так что, конечно, это может стать гораздо более сложным...
Концептуальный обзор
Основной единицей большинства решений pub/sub является канал сообщений. 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 запросы с содержимым сообщения в местоположения конечной точки публициста. Вы также можете публиковать сообщения через Websocket соединение в то же местоположение.
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
queued messages: 5
last requested: 18 sec. ago
active subscribers: 0
last message id: 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 и многокомпонентных подписчиков). Заголовок 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 поддерживает несколько различных типов подписчиков для получения сообщений: Websocket, EventSource (События, отправляемые сервером), Долгосрочное опрос, Интервальное опрос. HTTP с поэтапной передачей и HTTP многокомпонентный/смешанный.
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 не может автоматически различать запросы подписчиков долгосрочного опроса и интервального опроса, поэтому долгосрочное опрос должно быть отключено для местоположения подписчика, если вы хотите использовать интервальное опрос. -
Websocket
Двунаправленная связь для веб-браузеров. Часть спецификации 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. Это поведение можно настроить с помощью директивыnchan_subscriber_last_message_id. Тип содержимого сообщения не будет получен подписчиком EventSource, так как протокол не предусматривает эту метаданные. Ассоциированный типeventсообщения, если он присутствует, будет отправлен этому подписчику с помощью строкиevent:. -
HTTP multipart/mixed
MIME-тип
multipart/mixedбыл задуман для электронной почты, но почему бы не использовать его для HTTP? Его легко парсить и он включает метаданные с каждым сообщением. Инициируется включением заголовкаAccept: multipart/mixed. Заголовки ответа и неиспользуемая "предварительная" часть тела ответа отправляются сразу, с границей строки, сгенерированной случайным образом для каждого подписчика. Каждое последующее сообщение будет отправлено как одна часть многокомпонентного сообщения и будет включать время сообщения и тег (Last-ModifiedиEtag), а также необязательные заголовкиContent-Type. Каждое сообщение завершается следующей границей многокомпонентного сообщения без завершающего перевода строки. Хотя это соответствует спецификации многокомпонентного сообщения, это необычно, так как многокомпонентные сообщения определяются как начинающиеся, а не заканчивающиеся границей. Ассоциированный тип содержимого сообщения, если он присутствует, будет отправлен этому подписчику с заголовкомContent-Type. -
HTTP Raw Stream
Простой метод подписки, аналогичный подписчику потоковой передачи модуля Nginx HTTP Push Stream Module. Сообщения добавляются в тело ответа, разделенные переводом строки или настраиваемым с помощью
nchan_subscriber_http_raw_stream_separator. -
HTTP Chunked Transfer
Этот метод подписки использует
chunkedTransfer-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
channels: 10
subscribers: 0
messages: 219
shared memory used by messages: 42362 bytes
disk space used by messages: 0 bytes
limits:
max channels: 0
max subscribers: 0
max messages: 0
max messages shared memory: 0
max messages disk space: 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"
channels: 0
subscribers: 0
messages: 0
shared memory used by messages: 0 bytes
disk space used by messages: 0 bytes
limits:
max channels: 15
max subscribers: 1000
max messages: 0
max messages shared memory: 0
max messages disk space: 536870912
Лимиты применяются только локально, независимо от того, включен ли Redis.
Если запрос публициста или подписчика превышает лимит группы, Nchan ответит на него с ответом 403 Forbidden.
Хуки и обратные вызовы
Авторизация запроса
Эта функция, настраиваемая с помощью nchan_authorize_request, работает так же, как и модуль Nginx http_auth_request.
Рассмотрим конфигурацию:
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), интерпретируются как сбои авторизации. В этом случае сбойный ответ проксируется к клиенту.
Обратите внимание, что клиенты Websocket и EventSource будут пытаться авторизоваться только во время начального запроса рукопожатия, в то время как подписчики долгосрочного опроса и интервального опроса должны будут авторизоваться каждый раз, когда они запрашивают следующее сообщение, что может затопить ваше приложение слишком большим количеством запросов на авторизацию.
Присутствие подписчиков
Подписчики могут уведомлять приложение, когда они подписались и отписались от канала, используя настройки nchan_subscribe_request и nchan_unsubscribe_request.
Эти настройки должны указывать на местоположения Nginx, настроенные для пересылки запросов на upstream-прокси (ваше приложение):
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.
Код ответа upstream определяет, как будет продолжаться публикация:
- 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_groups.). Разные местоположения также могут подключаться к разным серверам Redis.
Nchan может работать с одним мастером Redis. Он также может автоматически обнаруживать и использовать слейвы Redis для балансировки трафика PUBSUB.
Redis Cluster
Nchan также поддерживает использование Redis Cluster, который добавляет масштабируемость за счет шардирования каналов между узлами кластера. Redis Cluster также обеспечивает автоматическую отказоустойчивость, высокую доступность и устраняет единую точку отказа одного общего сервера 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, nchan_redis_optimize_target может быть использован для предпочтения оптимизации слейвов Redis для ЦП или пропускной способности. Для тяжелых нагрузок публикации компромисс составляет примерно 35% пропускной способности репликации на слейв против 30% загрузки ЦП на слейвах.
Статистика производительности
Статистика команд Redis была добавлена в версии 1.3.5. Они предоставляют общее количество раз, когда различные команды Redis были выполнены, и общее время, которое они заняли. Статистика относится к данному экземпляру Nchan, а не ко всем серверам, подключенным к upstream Redis. Они сгруппированы по каждому 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.
Обратите внимание, что вы можете устанавливать любые пересылаемые заголовки здесь, как и в любом местоположении proxy_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 и Websocket. Подписчики долгосрочного опроса должны будут повторно аутентифицироваться для каждого нового сообщения, что может затопить ваше приложение слишком большим количеством запросов на аутентификацию.
Отзыв авторизации канала
В некоторых случаях вы можете захотеть отозвать авторизацию конкретного подписчика для данного канала (например, если изменяются разрешения пользователя). Если канал уникален для подписчика, это просто достигается удалением канала. То же самое можно сделать для общих каналов, подписав каждого подписчика как на общий канал, так и на канал, специфичный для подписчика, через мультиплексированное соединение. Удаление канала, специфичного для подписчика, завершит соединение подписчика, тем самым также завершив его подписку на общий канал. Рассмотрим следующую конфигурацию:
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 по умолчанию:
(пусто)контекст: server, location, ifУстановить строку комментария EventSource
: ...для периодических пингов от сервера к клиенту. Переводы строк не допускаются. Если пусто, комментарий не отправляется с пингом. -
nchan_eventsource_ping_data аргументы: 1 по умолчанию:
(пусто)контекст: 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 ]арг