Обложка: Видео: основы NGINX для начинающих за 200 секунд

Видео: основы NGINX для начинающих за 200 секунд

NGINX  — самый популярный веб-сервер в мире, используемый на абсолютном большинстве сайтов. Его выбирают в том числе для работы высоконагруженных ресурсов, так как он может обработать более чем десять тысяч соединений одновременно.

Подробности — в видео и текстовой расшифровке ниже.

Как устроен NGINX

NGINX построен на базе неблокирующей событийно-ориентированной архитектуры. У него есть один мастер-процесс, несколько воркер-процессов и два процесса, управляющих кэшем. Чтобы это увидеть, достаточно выполнить команду ps с ключами:

ps -ef --forest | grep nginx

Мастер-процесс запускается от суперпользователя и выполняет операции, требующие повышения прав, такие как:

  • чтение конфигурации,
  • открытие портов,
  • создание новых процессов.

Воркер-процессы выполняют всю работу:

  • обрабатывают сетевые соединения,
  • читают и пишут данные на диск,
  • общаются с бэкэнд-серверами.

Обычно количество воркер-процессов равняется количеству ядер CPU. Это позволяет использовать системные ресурсы максимально эффективно.

Воркер-процессы слушают два вида сокетов:

  • listener — для событий новых клиентов (запросов на соединение),
  • connection — для событий, которые требуют обработки.

Воркер-процесс ожидает событие, используя методы epoll или kqueue API операционной системы. Получив событие нового клиента на listener-сокете, воркер-процесс создаёт новый connection-сокет. Получив событие на connection-сокете, воркер-процесс обрабатывает этот запрос. После обработки события он не блокируется, а переходит в режим ожидания. Это позволяет минимизировать количество переключений контекстов операционной системы.

Другие два процесса управляют содержимым кэша на жестком диске:

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

При такой архитектуре для обновления конфигурации NGINX достаточно отправить мастер-процессу сигнал SIGHUP. Далее мастер-процесс создаст новые воркер-процессы с обновлённой конфигурацией и оповестит старые воркер-процессы о завершении работы. После этого воркер-процессы перестанут принимать новые соединения, а текущие соединения, обработав событие, будут закрываться (без ожидания keep-alive). Как только будут закрыты все соединения, воркер-процесс завершится. Это позволяет обновлять конфигурацию сервера без потери соединений, простоя ресурсов и прерывания обслуживания клиентов.

При правильно настроенном NGINX каждый воркер-процесс способен обработать сотни тысяч cоединений одновременно.

Основы конфигурации NGINX

Общий конфигурационный файл NGINX выглядит следующим образом:

# global context
user nginx; ## Default: nobody
worker_processes 5;  ## Default: 1
worker_rlimit_nofile 8192;
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
  worker_connections  4096; ## Default: 1024
}

http {
  # common http settings
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  gzip on;

  server {
    listen 80;
    server_name example.com;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    location / {
      proxy_buffers 4 256k;
      proxy_busy_buffers_size 256k;
      proxy_pass http://127.0.0.1:8081;
    }
  }

  # include directive
  include /etc/nginx/conf.d/*.conf;
}

Все настройки называются директивами и представляют собой пары key-value. Директива с фигурными скобками называется контекстом. Вот список основных контекстов:

  • global — общие настройки,
  • events — настройки обработки событий воркер-процессами,
  • http — настройки http- и https-соединений,
  • server — настройки виртуальных серверов,
  • location — настройки обработки и поиска идентификатора запроса.

Например, клиент делает запрос по URL http://www.example.com/blog. Протокол и доменное имя определяют, какой контекст server будет выбран, а идентификатор запроса (URI) определяет, какой контекст location будет использован.

Особого внимания требует директива include. Указанное значение для этой директивы — это регулярное выражение, которое описывает файлы в директории с расширением .conf. NGINX при старте найдёт все файлы, подходящие под регулярное выражение, и вставит их содержимое в то место, где указана директива include. Это даёт возможность разложить конфигурацию NGINX по отдельным файлам.

Конфигурации для разных случаев использования

NGINX обычно используется в трёх случаях:

  • в качестве reverse proxy для проксирования запросов в бекэнд,
  • как балансировщик запросов между серверами бекэнда,
  • для отдачи статического контента.

Начнём с конфигурации для отдачи статики. Создаём контекст server, указываем, какой порт слушать, задаём имя сервера и описываем три контекста location. Первый контекст — на все ресурсы, второй и третий контексты определяют директорию поиска файлов в зависимости от их расширения.

http {
  # ...
  server {
    listen 80;
    server_name example.com;
    location / {
      root /var/www/example;
    }

    location ~ \.(woff|woff2)$ {
      root /var/www/example/fonts;
    }
    location ~ \.(gif|jpg|png)$ {
      root /var/www/example/images;
    }
  }
}

Чтобы сделать reverse proxy, создаём такой же контекст server. В нём создаём один контекст location, в котором указываем директиву proxy_pass и URL, куда проксировать запросы. Теперь NGINX будет проксировать все запросы на указанный URL.

http {
  # ...
  server {
    listen 80;
    server_name domain.com;

    location / {
      proxy_pass http://app.domain.com;
    }
  }
}

Добавим балансировку в конфигурацию reverse proxy. Внутри контекста http создаём контекст upstream и указываем адреса наших приложений. Внутри контекста location указываем директиву proxy_pass со значением имени контекста upstream. Теперь NGINX  будет распределять запросы по двум серверам.

http {
  # ...
  upstream backend {
    server app1.domain.com;
    server app2.domain.com;
  }
  server {
    listen 80;
    server_name example.com;

    location / {
      proxy_pass http://backend;
    }
  }
}

Стратегия балансировки по умолчанию является round-robin — равномерным распределением. Можно указать стратегию least_conn, при которой NGINX будет отправлять запросы серверу, у которого меньше активных подключений. Это полезно, если серверы не одинаковые по своей мощности.

Группа автора «ВКонтакте», Telegram, Twitter.


Ещё у нас есть подборка книг на русском и английском + дополнительные материалы по NGINX.