Что нового в nginx?
Максим Дунин
Про ложь, наглую ложь и статистику
W3Techs:
0.x.x - 2.5%
1.x.x - 97.5%
Жизнь наладилась!
https://w3techs.com/technologies/details/ws-nginx/all/all
“Nginx is used by 31.4% of all the websites whose web server we know.”
Подробнее про 1.x.x
Новое:
1.10.x - 48.3%
1.11.x - 5.3%
Старое:
1.8.x - 10.3%
1.6.x - 9.5%
1.4.x - 8.3%
1.2.x - 5.6%
48.3
5.3
10.3
9.5
8.3
5.6
1.10.x
1.11.x
1.8.x
1.6.x
1.4.x
1.2.x
1.9.x
Научили nginx показывать порт клиента в различных местах, добавили знание о неидемпотентных запросах в
proxy_next_upstream, в кеш теперь можно писать асинхронно, а cache manager умеет следить за собой.
Появились динамические модули, worker_cpu_affinity обзавёлся ручкой auto для ленивых, модуль slice
позволяет загружать и кешировать большие файлы по частям, resolver научился делать запросы по TCP, HTTP/2
пришёл на смену SPDY, sub_filter теперь умеет два раза, nginx -T показывает конфиг, а nginx -V – версию
OpenSSL, “listen ... reuseport” для быстрой обработки новых соединений, и модуль stream для тех, кому и
целого HTTP мало.
Порт клиента
• set_real_ip_from теперь ставит не только адрес, но и порт
proxy_pass http://backend;
proxy_set_header X-Real-IP
$remote_addr:$remote_port;
• переменные $proxy_protocol_port,
$realip_remote_port
Идемпотентность
Идемпоте́нтность — свойство объекта или операции при повторном
применении операции к объекту давать тот же результат, что и при
одинарном.
GET, HEAD, PUT, DELETE, … – да
POST, LOCK, PATCH – нет
• Не повторяем неидемпотентные запросы
• Вернуть старое поведение:
proxy_next_upstream error timeout
non_idempotent;
Запись в кеш
Запись – это быстро
Но может и заблокироваться
Решение:
aio threads;
aio_write on;
Cache: боремся за память
Ошибки “could not allocate node”?
• Cache умеет удалять старые записи
• Но другой процесс может успеть раньше
Теперь cache manager следит за количеством записей.
Динамические модули
• Упростить сборку пакетов
• внешние зависимости у модулей!
• Упростить отладку
• 3rd party модули должно быть просто выключить
Динамические модули
Собрать:
./configure --with-http_image_filter_module=dynamic
./configure --add-dynamic-module=/path/to/module
nginx.conf:
load_module modules/ngx_http_image_filter_module.so;
Динамическая загрузка своего модуля
• Меняем config-скрипт на auto/module
• Для сложных модулей:
• ngx_count_modules()
• ngx_modules меняем на cycle->modules
Динамическая загрузка своего модуля
Было:
ngx_addon_name="ngx_http_delay_module"
HTTP_MODULES="$HTTP_MODULES ngx_http_delay_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_delay_module.c"
Стало:
ngx_addon_name="ngx_http_delay_module"
ngx_module_type=HTTP
ngx_module_name=ngx_http_delay_module
ngx_module_incs=
ngx_module_deps=
ngx_module_srcs=$ngx_addon_dir/ngx_http_delay_module.c
ngx_module_libs=
. auto/module
CPU affinity
Пример из документации:
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
Что делать, если у нас много процессоров?
worker_cpu_affinity auto;
worker_cpu_affinity auto 0101010101010101;
Кешируем большие файлы
Проблемы:
• С бекенда скачивается файл целиком
• Range-запросы ждут начала файла
• Часто нужно только начало
Решение:
• Качать и кешировать кусками
Модуль slice
location / {
slice 1m;
proxy_cache cache;
proxy_cache_key $uri$is_args$args$slice_range;
proxy_set_header Range $slice_range;
proxy_cache_valid 200 206 1h;
proxy_pass http://upstream;
}
• Подзапросы на отдельные части
• Кешируем отдельные части
SPDY умер, HTTP/2 за него
server {
listen 443 ssl http2;
...
}
• Мультиплексирование запросов в одном соединении
• Теперь работает proxy_request_buffering
• Недоделанность реализаций всё там же, осторожнее
Несколько sub_filter за раз
Пример:
sub_filter http://one.example.com https://one.example.com;
sub_filter http://two.example.com https://two.example.com;
sub_filter_once off;
Заодно он научился делать это быстрее.
Быстрая обработка новых соединений
• Тестируем
• accept_mutex!
• Один listen-сокет – contention в
ядре
listen 80 reuseport;
0
50
100
150
200
0 6 12 18 24
kr/s, E5645 (6 ядер / 12 потоков) x 2
Stream: для тех, кому HTTP мало
stream {
upstream backend {
server 10.0.0.2:12345;
server 10.0.0.3:12345;
}
server {
listen 12345;
proxy_pass backend;
}
}
• Балансировка произвольных соединений
• SSL от клиентов, SSL к бекендам
• Ограничения количества соединений и скорости
• PROXY protocol к бекендам
• … и даже UDP
Разное
• Resolver научился TCP
• Блоки upstream{} в разделяемой памяти
• Разделяемая память на Windows с ASLR (Vista и новее)
• SSLv3 по умолчанию запрещён
• $upstream_connect_time
• Полный конфиг по “nginx -T”
• Версия OpenSSL в “nginx -V”
nginx version: nginx/1.11.2
built by gcc 4.9.2 (Debian 4.9.2-10)
built with OpenSSL 1.0.1k 8 Jan 2015 (running with OpenSSL 1.0.1t 3 May 2016)
...
Всё это доступно в nginx 1.10.2
1.11.x
Переменные в модуле stream, возможность "подсматривать" в SSL handshake, и множество всего ещё. Больше
нет quick recovery, но есть max_conns, а cache manager научился быть незаметным, proxy_bind теперь умеет
transparent, и умеет использовать IP_BIND_ADDRESS_NO_PORT. Мы выключили accept_mutex, научились
использовать EPOLLEXCLUSIVE вместо него, и начали полагаться на EPOLLRDHUP, map научился сложным
значениям, переменная $request_id для злопамятных. Теперь можно несколько SSL-сертификатов (наконец-то
RSA и ECDSA одновременно!), умеем списки кривых для ECDH, выключили DH, упростили сборку динамических
модулей.
Stream: переменные
А также map, return, geo, geoip, split_clients, real ip, access log…
Теперь можно:
map $remote_addr $limit {
127.0.0.1 "";
default $binary_remote_addr;
}
limit_conn_zone $limit zone=addr:10m;
limit_conn addr 1;
Stream: $ssl_preread_server_name
Если нужно посмотреть в SSL-соединение,
но нельзя снимать SSL:
map $ssl_preread_server_name $backend {
backend.example.com 192.0.2.1:12345;
default 192.0.2.2:12345;
}
server {
listen 12345;
proxy_pass $backend;
ssl_preread on;
}
Количество соединений к бекендам
Пример:
upstream u {
server 192.0.2.1:8080 max_conns=10;
server 192.0.2.2:8080 max_conns=10;
server 192.0.2.3:8080 max_conns=10;
}
Исходно для NGINX Plus.
Transparent proxy
Передать адрес клиента, традиционные решения:
• X-Forwarded-For / X-Real-IP
• PROXY protocol
Если очень надо:
proxy_bind $remote_addr transparent;
SO_BINDANY (NetBSD), IP_TRANSPARENT (Linux), IP_BINDANY (FreeBSD),
нужен root
Linux и IP_BIND_ADDRESS_NO_PORT
Сколько соединений можно установить к одному бекенду?
К двум?
А теперь пишем в конфиг:
proxy_bind 192.0.2.1;
и всё плохо. Почему?
• Bind() выбирает локальный порт
• IP_BIND_ADDRESS_NO_PORT (Linux 4.2, glibc 2.22)
Accept mutex, Linux и EPOLLEXCLUSIVE
Thundering herd problem.
Традиционный ответ – accept mutex.
Но:
• вообще-то у нас процессов мало
• часто мешает в тестах
• нельзя использовать на Windows
• не нужен с “listen … reuseport”
• на Linux появился EPOLLEXCLUSIVE (Linux 4.5, glibc 2.24)
Accept mutex, Linux и EPOLLEXCLUSIVE
Новый default:
accept_mutex off;
Ну и EPOLLEXCLUSIVE поддерживаем.
SSL и сертификаты
RSA – совместимо, но дорого
ECDSA – быстро, но не будет работать в XP (Android до 4.0, OpenSSL до 1.0.0)
rsa2048: 400 signs/s
ecdsap256: 5400 signs/s
Теперь можно так:
ssl_certificate example.com.rsa.crt;
ssl_certificate_key example.com.rsa.key;
ssl_certificate example.com.ecdsa.crt;
ssl_certificate_key example.com.ecdsa.key;
300
1000
ECDHE-RSA
ECDHE-ECDSA
SSL и другое
• ssl_ecdh_curve умеет список кривых (OpenSSL 1.0.2+)
• “auto” по умолчанию
• OpenSSL 1.1.0: X25519:prime256v1:secp521r1:secp384r1
• ssl_dhparam по умолчанию отсутствует
• DHE-шифры выключены
• Медленно
• Атаки на DHE, weakdh.org
Динамические модули: совместимость
Проблема:
• Cтруктуры зависят от опций сборки
• Собирать модули надо с теми же опциями
Теперь проще:
./configure --with-compat ...
./configure --with-compat --add-dynamic-module=/path/to/module
Бонус: совместимость с NGINX Plus.
Разное
• На EPOLLRDHUP мы теперь полагаемся, если ядро новое
• HTTP/2 – исправления и улучшения
• Map научился сложным комбинациям переменных и значений
map $host $log {
~foo /var/log/$host.log;
default /var/log/default.log;
}
• $request_id
Всё это доступно в nginx 1.11.5
Still counting
Где взять дене^Wсвежий nginx?
• Исходные коды, как обычно:
http://nginx.org/ru/download.html
• Для FreeBSD:
используйте порты nginx и nginx-devel, там всё новое
Спасибо Сергею Осокину!
• Для Linux разных версий:
системные пакеты – обычно старые, свежие пакеты доступны на
http://nginx.org/ru/linux_packages.html
(отдельные пакеты для модулей geoip, image filter, njs, perl, xslt)
Спасибо!
Вопросы?
Максим Дунин
mdounin@mdounin.ru

Что нового в nginx? / Максим Дунин (Nginx, Inc.)

  • 1.
    Что нового вnginx? Максим Дунин
  • 2.
    Про ложь, наглуюложь и статистику W3Techs: 0.x.x - 2.5% 1.x.x - 97.5% Жизнь наладилась! https://w3techs.com/technologies/details/ws-nginx/all/all “Nginx is used by 31.4% of all the websites whose web server we know.”
  • 3.
    Подробнее про 1.x.x Новое: 1.10.x- 48.3% 1.11.x - 5.3% Старое: 1.8.x - 10.3% 1.6.x - 9.5% 1.4.x - 8.3% 1.2.x - 5.6% 48.3 5.3 10.3 9.5 8.3 5.6 1.10.x 1.11.x 1.8.x 1.6.x 1.4.x 1.2.x
  • 4.
    1.9.x Научили nginx показыватьпорт клиента в различных местах, добавили знание о неидемпотентных запросах в proxy_next_upstream, в кеш теперь можно писать асинхронно, а cache manager умеет следить за собой. Появились динамические модули, worker_cpu_affinity обзавёлся ручкой auto для ленивых, модуль slice позволяет загружать и кешировать большие файлы по частям, resolver научился делать запросы по TCP, HTTP/2 пришёл на смену SPDY, sub_filter теперь умеет два раза, nginx -T показывает конфиг, а nginx -V – версию OpenSSL, “listen ... reuseport” для быстрой обработки новых соединений, и модуль stream для тех, кому и целого HTTP мало.
  • 5.
    Порт клиента • set_real_ip_fromтеперь ставит не только адрес, но и порт proxy_pass http://backend; proxy_set_header X-Real-IP $remote_addr:$remote_port; • переменные $proxy_protocol_port, $realip_remote_port
  • 6.
    Идемпотентность Идемпоте́нтность — свойствообъекта или операции при повторном применении операции к объекту давать тот же результат, что и при одинарном. GET, HEAD, PUT, DELETE, … – да POST, LOCK, PATCH – нет • Не повторяем неидемпотентные запросы • Вернуть старое поведение: proxy_next_upstream error timeout non_idempotent;
  • 7.
    Запись в кеш Запись– это быстро Но может и заблокироваться Решение: aio threads; aio_write on;
  • 8.
    Cache: боремся запамять Ошибки “could not allocate node”? • Cache умеет удалять старые записи • Но другой процесс может успеть раньше Теперь cache manager следит за количеством записей.
  • 9.
    Динамические модули • Упроститьсборку пакетов • внешние зависимости у модулей! • Упростить отладку • 3rd party модули должно быть просто выключить
  • 10.
    Динамические модули Собрать: ./configure --with-http_image_filter_module=dynamic ./configure--add-dynamic-module=/path/to/module nginx.conf: load_module modules/ngx_http_image_filter_module.so;
  • 11.
    Динамическая загрузка своегомодуля • Меняем config-скрипт на auto/module • Для сложных модулей: • ngx_count_modules() • ngx_modules меняем на cycle->modules
  • 12.
    Динамическая загрузка своегомодуля Было: ngx_addon_name="ngx_http_delay_module" HTTP_MODULES="$HTTP_MODULES ngx_http_delay_module" NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_delay_module.c" Стало: ngx_addon_name="ngx_http_delay_module" ngx_module_type=HTTP ngx_module_name=ngx_http_delay_module ngx_module_incs= ngx_module_deps= ngx_module_srcs=$ngx_addon_dir/ngx_http_delay_module.c ngx_module_libs= . auto/module
  • 13.
    CPU affinity Пример издокументации: worker_processes 4; worker_cpu_affinity 0001 0010 0100 1000; Что делать, если у нас много процессоров? worker_cpu_affinity auto; worker_cpu_affinity auto 0101010101010101;
  • 14.
    Кешируем большие файлы Проблемы: •С бекенда скачивается файл целиком • Range-запросы ждут начала файла • Часто нужно только начало Решение: • Качать и кешировать кусками
  • 15.
    Модуль slice location /{ slice 1m; proxy_cache cache; proxy_cache_key $uri$is_args$args$slice_range; proxy_set_header Range $slice_range; proxy_cache_valid 200 206 1h; proxy_pass http://upstream; } • Подзапросы на отдельные части • Кешируем отдельные части
  • 16.
    SPDY умер, HTTP/2за него server { listen 443 ssl http2; ... } • Мультиплексирование запросов в одном соединении • Теперь работает proxy_request_buffering • Недоделанность реализаций всё там же, осторожнее
  • 17.
    Несколько sub_filter зараз Пример: sub_filter http://one.example.com https://one.example.com; sub_filter http://two.example.com https://two.example.com; sub_filter_once off; Заодно он научился делать это быстрее.
  • 18.
    Быстрая обработка новыхсоединений • Тестируем • accept_mutex! • Один listen-сокет – contention в ядре listen 80 reuseport; 0 50 100 150 200 0 6 12 18 24 kr/s, E5645 (6 ядер / 12 потоков) x 2
  • 19.
    Stream: для тех,кому HTTP мало stream { upstream backend { server 10.0.0.2:12345; server 10.0.0.3:12345; } server { listen 12345; proxy_pass backend; } } • Балансировка произвольных соединений • SSL от клиентов, SSL к бекендам • Ограничения количества соединений и скорости • PROXY protocol к бекендам • … и даже UDP
  • 20.
    Разное • Resolver научилсяTCP • Блоки upstream{} в разделяемой памяти • Разделяемая память на Windows с ASLR (Vista и новее) • SSLv3 по умолчанию запрещён • $upstream_connect_time • Полный конфиг по “nginx -T” • Версия OpenSSL в “nginx -V” nginx version: nginx/1.11.2 built by gcc 4.9.2 (Debian 4.9.2-10) built with OpenSSL 1.0.1k 8 Jan 2015 (running with OpenSSL 1.0.1t 3 May 2016) ...
  • 21.
  • 22.
    1.11.x Переменные в модулеstream, возможность "подсматривать" в SSL handshake, и множество всего ещё. Больше нет quick recovery, но есть max_conns, а cache manager научился быть незаметным, proxy_bind теперь умеет transparent, и умеет использовать IP_BIND_ADDRESS_NO_PORT. Мы выключили accept_mutex, научились использовать EPOLLEXCLUSIVE вместо него, и начали полагаться на EPOLLRDHUP, map научился сложным значениям, переменная $request_id для злопамятных. Теперь можно несколько SSL-сертификатов (наконец-то RSA и ECDSA одновременно!), умеем списки кривых для ECDH, выключили DH, упростили сборку динамических модулей.
  • 23.
    Stream: переменные А такжеmap, return, geo, geoip, split_clients, real ip, access log… Теперь можно: map $remote_addr $limit { 127.0.0.1 ""; default $binary_remote_addr; } limit_conn_zone $limit zone=addr:10m; limit_conn addr 1;
  • 24.
    Stream: $ssl_preread_server_name Если нужнопосмотреть в SSL-соединение, но нельзя снимать SSL: map $ssl_preread_server_name $backend { backend.example.com 192.0.2.1:12345; default 192.0.2.2:12345; } server { listen 12345; proxy_pass $backend; ssl_preread on; }
  • 25.
    Количество соединений кбекендам Пример: upstream u { server 192.0.2.1:8080 max_conns=10; server 192.0.2.2:8080 max_conns=10; server 192.0.2.3:8080 max_conns=10; } Исходно для NGINX Plus.
  • 26.
    Transparent proxy Передать адресклиента, традиционные решения: • X-Forwarded-For / X-Real-IP • PROXY protocol Если очень надо: proxy_bind $remote_addr transparent; SO_BINDANY (NetBSD), IP_TRANSPARENT (Linux), IP_BINDANY (FreeBSD), нужен root
  • 27.
    Linux и IP_BIND_ADDRESS_NO_PORT Сколькосоединений можно установить к одному бекенду? К двум? А теперь пишем в конфиг: proxy_bind 192.0.2.1; и всё плохо. Почему? • Bind() выбирает локальный порт • IP_BIND_ADDRESS_NO_PORT (Linux 4.2, glibc 2.22)
  • 28.
    Accept mutex, Linuxи EPOLLEXCLUSIVE Thundering herd problem. Традиционный ответ – accept mutex. Но: • вообще-то у нас процессов мало • часто мешает в тестах • нельзя использовать на Windows • не нужен с “listen … reuseport” • на Linux появился EPOLLEXCLUSIVE (Linux 4.5, glibc 2.24)
  • 29.
    Accept mutex, Linuxи EPOLLEXCLUSIVE Новый default: accept_mutex off; Ну и EPOLLEXCLUSIVE поддерживаем.
  • 30.
    SSL и сертификаты RSA– совместимо, но дорого ECDSA – быстро, но не будет работать в XP (Android до 4.0, OpenSSL до 1.0.0) rsa2048: 400 signs/s ecdsap256: 5400 signs/s Теперь можно так: ssl_certificate example.com.rsa.crt; ssl_certificate_key example.com.rsa.key; ssl_certificate example.com.ecdsa.crt; ssl_certificate_key example.com.ecdsa.key; 300 1000 ECDHE-RSA ECDHE-ECDSA
  • 31.
    SSL и другое •ssl_ecdh_curve умеет список кривых (OpenSSL 1.0.2+) • “auto” по умолчанию • OpenSSL 1.1.0: X25519:prime256v1:secp521r1:secp384r1 • ssl_dhparam по умолчанию отсутствует • DHE-шифры выключены • Медленно • Атаки на DHE, weakdh.org
  • 32.
    Динамические модули: совместимость Проблема: •Cтруктуры зависят от опций сборки • Собирать модули надо с теми же опциями Теперь проще: ./configure --with-compat ... ./configure --with-compat --add-dynamic-module=/path/to/module Бонус: совместимость с NGINX Plus.
  • 33.
    Разное • На EPOLLRDHUPмы теперь полагаемся, если ядро новое • HTTP/2 – исправления и улучшения • Map научился сложным комбинациям переменных и значений map $host $log { ~foo /var/log/$host.log; default /var/log/default.log; } • $request_id
  • 34.
    Всё это доступнов nginx 1.11.5 Still counting
  • 35.
    Где взять дене^Wсвежийnginx? • Исходные коды, как обычно: http://nginx.org/ru/download.html • Для FreeBSD: используйте порты nginx и nginx-devel, там всё новое Спасибо Сергею Осокину! • Для Linux разных версий: системные пакеты – обычно старые, свежие пакеты доступны на http://nginx.org/ru/linux_packages.html (отдельные пакеты для модулей geoip, image filter, njs, perl, xslt)
  • 36.

Editor's Notes

  • #3 Жизнь наладилась - уже почти никто не использует 0.x.x. Наиболее популярная 0.x.x версия - 0.7.67. Казалось бы, при чём тут Debian 6 (Squeeze)?
  • #4 Более 40% на старых версиях, 50% - на новых. Не так плохо. И видно, что все уже выучили: чётные версии стабильные, нечётные - mainline. Сегодня мы поговорим о том, что же нового появилось в 1.10.x и 1.11.x,то есть о том, что вы получаете, если обновитесь, если ещё не сделали этого. Или что вы уже получили, но ещё не знаете об этом - если вы уже обновились.
  • #16 Модуль делает подзапросы один за другим, и склеивает ответы. А кеш - кеширует ответы на подзапросы. Множество ограничений (файлы нельзя менять, бекенд должен уметь range-запросы, память тратится на буфера), но очень эффективное кеширование.
  • #17 Отличия от SPDY невелики, логика всё та же: сделаем мультиплексирование сами, не полагаясь на TCP. Свои плюсы и свои минусы.
  • #19 Дополнительные эффекты: можно запустить много программ на одном listen-сокете, перестаёт работать ограничение Linux'а на одновременное создание listen-сокетов на INADDR_ANY и на IP-адресе.
  • #20 Можно балансировать, убирать/добавлять SSL, ограничивать соединения и поток данных в каждом соединении. Можно даже UDP.
  • #21 Resolver: 512-байт лимит UDP, 30 A-записей, EDNS0 – не решение,
  • #24  То же, что и в HTTP.
  • #26 Пример того, как разработки из NGINX Plus попадают в nginx. Заодно убрали quick recovery - механизм, который "оживлял" все бекенды.
  • #31 OpenSSL 1.0.1f: rsa2048 400 sings/s, ecdsap256 5400 signs/s OpenSSL 1.0.2j: 600, 12000 Requests: rsa2048 295.40 handshakes/s, ecdsap256 890.35/1009.17/1003.70 handshakes/s (cached 4000 handshakes/s) ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384