Печенюшка - Веб-сервер nginx

Веб-сервер nginx. Частина 1: Загальний огляд та базове налаштування

nginx (engine x) – це HTTP-сервер та IMAP/POP3 проксі-сервер для UNIX-подібних платформ (FreeBSD та GNU/Linux). Nginx почав розроблятись Ігорем Сисоєвим, співробітником компанії Рамблер навесні 2002 року, а восени 2004 року з'явився перший публічно доступний реліз. Він, як і наступні, поширюється під ліцензією BSD.

На даний момент nginx працює на великій кількості високонавантажених сайтів (серед них - Рамблер, Яндекс, Контакт, wordpress.com, Wrike та інші). Поточна версія 0.6.x розглядається як стабільна з точки зору надійності, а релізи з гілки 0.7 вважаються нестабільними. При цьому важливо помітити, що функціональність деяких модулів змінюватиметься, внаслідок чого можуть змінюватися і директиви, тому зворотної сумісності nginx до версії 1.0.0 не гарантується.

Чим же nginx такий гарний і чому його так люблять адміністратори високонавантажених проектів? Чому б просто не використовувати Apache?

Чому Apache – погано?

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

  1. Послідовна. Сервер відкриває сокет, що слухає, і чекає, коли з'явиться з'єднання (під час очікування він знаходиться в заблокованому стані). Коли з'єднання приходить, сервер обробляє його в тому ж контексті, закриває з'єднання і знову чекає з'єднання. Очевидно, це далеко не найкращий спосіб, особливо коли робота з клієнтом ведеться досить довго і багато підключень. Крім того, у послідовній моделі є ще багато недоліків (наприклад, неможливість використання кількох процесорів) і в реальних умовахвона мало використовується.
  2. Багатопроцесна (багатопоточна). Сервер відкриває сокет, що слухає. Коли приходить з'єднання, він приймає його, після чого створює (або бере з пулу заздалегідь створених) новий процес або потік, який може як завгодно довго працювати зі з'єднанням, а по закінченні роботи завершитися або повернутися в пул. Головний потік тим часом готовий прийняти нове з'єднання. Це найбільш популярна модель, тому що вона відносно просто реалізується, дозволяє виконувати складні та довгі обчислення для кожного клієнта та використовувати усі доступні процесори. Приклад її використання – Web-сервер Apache. Однак цей підхід має й недоліки: при великій кількості одночасних підключень створюється дуже багато потоків (або, що ще гірше, процесів), і операційна система витрачає багато ресурсів на перемикання контексту. Особливо погано, коли клієнти дуже повільно приймають контент. Виходять сотні потоків чи процесів, зайнятих лише відправкою даних повільним клієнтам, що створює додаткове навантаження на планувальник ОС, збільшує кількість переривань і споживає багато пам'яті.
  3. Неблоковані сокети/кінцевий автомат. Сервер працює в рамках одного потоку, але використовує неблоковані сокети та механізм полінгу. Тобто. сервер на кожній ітерації нескінченного циклу вибирає зі всіх сокетів той, що готовий для прийому/надсилання даних за допомогою виклику select(). Після того, як сокет вибраний, сервер відправляє на нього дані або читає їх, але не чекає підтвердження, а переходить у початковий стан і чекає на події на іншому сокеті або ж обробляє наступний, в якому подія відбулася під час обробки попереднього. Ця модель дуже ефективно використовує процесор та пам'ять, але досить складна у реалізації. Крім того,в рамках цієї моделі обробка події на сокеті повинна відбуватися дуже швидко - інакше в черзі буде накопичуватися багато подій, і врешті-решт вона переповниться. Саме за такою моделлю працює nginx. З іншого боку, дозволяє запускати кілька робочих процесів (так званих workers), тобто. може використовувати кілька процесорів.

Отже, уявимо таку ситуацію: на HTTP-сервер з каналом в 1 Гбіт/с підключається 200 клієнтів з каналом по 256 Кбіт/с:

Що відбувається у випадку Apache? Створюється 200 потоків/процесів, які відносно швидко генерують контент (це можуть бути як динамічні сторінки, так і статичні файли з диска), але повільно віддають його клієнтам. Операційна система змушена справлятися з купою потоків та блокувань введення/виводу.

Nginx у такій ситуації витрачає на кожен коннект на порядок менше ресурсів ОС та пам'яті. Але тут виявляється обмеження мережевої моделі nginx: не може генерувати динамічний контент у собі, т.к. це призведе до блокування всередині nginx. Звичайно, рішення є: nginx вміє проксувати такі запити (на генерування контенту) на будь-який інший веб-сервер (наприклад, той самий Apache) або на FastCGI-сервер.

Розглянемо механізм роботи зв'язки nginx як «головного» сервера та Apache як сервер для генерації динамічного контенту:

Nginx приймає з'єднання від клієнта та читає від нього весь запит. Тут слід зазначити, що доки nginx не прочитав весь запит, він не віддає його на обробку. Через це зазвичай "ламаються" практично всі індикатори прогресу закачування файлів - втім, існує можливість відремонтувати їх за допомогою стороннього модуля upload_progress (це вимагатиме модифікації програми).

Після того якnginx прочитав всю відповідь, він відкриває з'єднання Apache. Останній виконує свою роботу (генерує динамічний контент), після чого віддає свою відповідь nginx, який буферизує його в пам'яті або тимчасовому файлі. Тим часом Apache звільняє ресурси. Далі nginx повільно віддає контент клієнту, витрачаючи при цьому на порядки менше ресурсів, ніж Apache.

Така схема називається фронтенд + бекенд (frontend + backend) і застосовується дуже часто.

Т.к. nginx тільки починає завойовувати популярність, є деякі проблеми з бінарними пакетами, тому будьте готові до того, що його доведеться компілювати самостійно. З цим зазвичай не виникає проблем, треба лише уважно прочитати висновок команди ./configure -help і вибрати необхідні вам опції компіляції, наприклад:

./configure \ —prefix=/opt/nginx-0.6.x \ # префікс установки —conf-path=/etc/nginx/nginx.conf \ # розташування конфігураційного файлу —pid-path =/var/run/nginx.pid \ # … та pid-файлу —user=nginx \ # ім'я користувача під яким буде запускатися nginx —with-http_ssl_module —with-http_gzip_static_module —with-http_stub_status_module \ # список потрібних —without-http_ssi_module —without-http_userid_module —without-http_autoindex_module —without-http_geo_module —without-http_referer_module —without-http_memcached_module —without-http_limit_zone_module

Після налаштування варто запустити стандартний make && make install, після чого можна скористатися nginx.

Крім того, у Gentoo ви можете скористатися ebuild'ом зі стандартного дерева портів; у RHEL/CentOS репозиторієм epel (у ньому розташовані nginx 0.6.x) або srpm для версії 0.7, який можна завантажити звідси: http://blogs.mail.ru/community/nginx; у Debianможна скористатися пакетом nginx із гілки unstable.

Конфігураційний файл

Конфігураційний файл nginx дуже зручний та інтуїтивно зрозумілий. Він називається зазвичай nginx.conf і розміщується в $prefix/conf/ якщо розташування не було перевизначено при компіляції. Я люблю класти його у /etc/nginx/, також роблять і розробники всіх пакетів згаданих вище.

Структура конфігураційного файлу така:

user nginx; ім'я користувача, з правами якого запускатиметься nginx worker_processes 1; # кількість робочих процесів events # у цьому блоці вказується механізм полінгу який буде використовуватися (див. нижче) та максимальна кількість можливих підключень >

а так можна визначити location, для якого можна також перевизначити практично всі директиви зазначені на більш глобальних рівнях location /abcd/ ; > # Крім того, можна зробити location за регулярним виразом, наприклад так: location

# інший сервер server listen *: 80; server_name ccc.bbb;

Зверніть увагу, що кожна директива повинна закінчуватися крапкою з комою. Зворотне проксування та FastCGI

Отже, вище ми розглянули переваги схеми frontend + backend, розібралися з установкою, структурою та синтаксисом конфігураційного файлу, розглянемо як реалізувати зворотне проксування в nginx.

А дуже просто! Наприклад так:

location/proxy_pass http://1.2.3.4:8080; >

У цьому прикладі всі запити, що потрапляють в location/проксуватимуться на сервер 1.2.3.4 порт 8080. Це може бути як apache, так і будь-який інший http-сервер.

Конфігурація nginx у такому разі виглядає так:

Інший варіант бекенд - це використання FastCGI. Уу цьому випадку конфігурація nginx виглядатиме приблизно так:

# location, в який будуть потрапляти запити на php-скрипти location

# та деякі параметри, які потрібно передати серверу fastcgi, щоб він зрозумів який скрипт і з якими параметрами виконувати: fastcgi_param SCRIPT_FILENAME /usr/www/html$fastcgi_script_name; ім'я скрипта fastcgi_param QUERY_STRING $query_string; # рядок запиту # та параметри запиту: fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; >

# завдяки тому, що локейшени з регулярними виразами мають великий «пріоритет», сюди потраплятимуть всі не-php запити.

location / root /var/www/html/ >

Для того, щоб менше навантажувати бекенд, статичні файли краще віддавати тільки через nginx - він, з цією задачею справляється краще, т.к. на кожен запит він витрачає значно менше ресурсів (не треба породжувати новий процес, але процес nginx'а зазвичай споживає менше пам'яті, а обслуговувати може багато з'єднань).

У конфігураційному файлі це виглядає приблизно так:

server listen *: 80; server_name myserver.com;

# припустимо, що всі статичні файли лежать у /files location /files/ root /var/www/html/; # вказуємо шлях на фс expiras 14d; # додаємо заголовок Expires: error_page 404 = @back; а якщо файл не знайдений, відправляємо його в іменований локейшн @back >

# запити з /files, для яких не було знайдено файл відправляємо на backend, а він може або згенерувати потрібний файл, або показати красиве повідомлення про помилку location @back proxy_pass » title=»http://127.0. 0.1: 80;

Якщо вся статика не вміщена вякийсь певний каталог, то скористатися регулярним виразом:

* ^.+\.(jpgjpeggifpngicocssziptgzgzrarbz2docxlsexepdfppttxttarwavbmprtfjs)$ # аналогічно тому що вище, тільки в цей location будуть потрапляти всі запити, що закінчуються на один із зазначених суфіксів root /var/www/html/; error_page 404 = @back; >

To be continued

Продовження статті вже можна прочитати в OpenSource #042 або найближчим часом на цьому сайті.

Тут можна знайти додаткову інформацію про nginx: