21 июн 2021

Как php взаимодействует с веб-сервером?

#php, #http, #apache, #nginx, #php-fpm

При изучении php вопрос коммуникации интерпретатора и сервера часто рассматривается поверхностно или в принципе выносится за рамки. В этой статье я расскажу о различных способах взаимодействия, в том числе: cgi, fast-cgi, mod_apache, php-fpm и о том как они устроены. Это позволит вам сделать оптимальный выбор при проектировании системы, а также управлять её быстродействием.

Как php взаимодействует с веб-сервером?

Web-сервер

В терминах веб-разработки веб-сервер - это программа(служба) призванная обрабатывать http-запросы. Компьютер (виртуальная система), где установлена это программа, обычно называют машиной или "тачкой" на сленге. Каждый раз, когда пользователь вводит в браузере URL, соответствующий http-запрос отправляется на сервер. Веб-сервер(Apache, Nginx или любой другой) разбирает(парсит) это запрос и отдает запрошенный документ(если он имеется и доступен). Браузер в данной схеме принято называть клиентом.

Типичный http-запрос выглядит так:


  GET /document.html HTTP/1.1
  Host: alexp007.ru
  User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

В первой строке указывается метод, запрашиваемый ресурс и протокол. Дальше следуют(опционально) заголовки - это текстовая информация формата "ключ: значение", позволяющая передавать различные дополнительные сведения, например версию браузера(клиента) и принимаемые типы документов.

Ответ сервера:


  HTTP/1.1 200 OK
  Server: nginx
  Content-Type: text/html; charset=UTF-8
  Content-length: 194

  <!DOCTYPE html>
  <html> lang=ru>
  <head>
    <title>Документ</title>
  </head>
  <body>
    Тело документа.
  </body>
  </html>

Динамический контент

Изначально веб-серверы работали только со статическим контентом, отдавали html-страницы, jpeg картинки и прочее. Однако, с развитием интернета появилась необходимость работать с динамическим контентом(создаваемым на лету). Динамика обогащает пользовательский опыт и превращает простые сайты в настоящие веб-сервисы. Тут на сцену и выходит php вместе с cgi.

Common Gateway Interface

Интерфейс описывающий взаимодействие между сервером и программой(скриптом). Каждый раз, когда приходит запрос на исполнение соответствующего скрипта, сервер поднимает дополнительный процесс, который запускает интерпретатор php и полученный результат возвращает клиенту. По сути дела интерпретатор запускается в режиме cli (STDIN/STDOUT). Схему можно представить так:

Схема взаимодействия сервера с CGI и PHP

Запрос от клиента поступает на сервер, если запрашиваемый документ статический и находится на сервере, то сервер просто отдает его. Если же документ(тип документа) является динамическим, то будет поднят новый процесс, который через интерфейс CGI запустит php-скрипт, а результат его работы вернет клиенту.

Программист разрабатывающий cgi-скрипты должен позаботится об ответе состоящим из заголовков и тела в соответствии с протоколом http. Например, для простого сценария, возвращающего html, обязательно должен быть установлен Content-type.

Пример cgi-программы:

#!/usr/bin/php
<?php

echo "Content-type: text/html; charset=utf-8\n\n"
echo '<h1>Привет МИР!</h1>';

Обратите внимание на первую строчку #!/usr/bin/php - это указание веб-серверу на интерпретатор php, который необходимо вызвать, чтобы исполнить код.

Плюсы и минусы CGI

Поскольку серверу для исполнения cgi-скрипта необходимо каждый раз создавать процесс и поднимать интерпретатор, то накладные расходы на запуск таких программ достаточно высоки, а скорость исполнения мала. Более того, все скрипты запускается от пользователя веб-сервера, что несет в себе потенциальную угрозу и не позволяет разделять права. Такие приложения очень сложно поддаются отладке, потому что при ошибке php, сервер просто перестанет выполнять запрос и вернет пользователю 500 статус, а в худшем случае может и упасть сам. CGI не позволяет использовать opcache (кеширование исполняемого кода php), что также отражается на производительности.

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

Apache mod_php

Самый распространенный вариант взаимодействия сервера и php это Apache + mod_php, хотя его популярность давно уже прошла и он понемногу уступает место более современному php-fpm (о нём мы поговорим позже в этой статье). Этот способ быстр в установке, настройке и обладает хорошей производительностью при запуске php-программ.

Суть в том, что Apache запускается вместе со встроенным интерпретатором php и может самостоятельно исполнять скрипты. Этот режим также позволяет использовать opcache. За счет этих двух факторов, динамика отдается значительно быстрее чем при CGI, однако есть небольшое отставание по статике (ведь теперь при любом запросе загружается интерпретатор php). Отсюда и появилась некогда популярная связка Nginx + Apache + mod_php. Nginx быстро отдает статику, а Apache динамику.

Минус тот же, что и при CGI - php-скрипты запускаются с привилегиями пользователя веб-сервера. Надо признаться, что способ разделить пользователей всё же существует suPHP.

FastCGI

Это более продвинутый и быстрый CGI. При использовании FastCGI сервер не создает для каждого запроса новый процесс, а использует один из заранее подготовленных и ожидающих процессов. Этот режим позволяет гибко настраивать взаимодействие: кол-во процессов, срок жизни, время исполнения и прочее.

При запуске сервера, веб-сервер создает процессы, которые должны будут обрабатывать все php-программы. Это происходит с помощью скриптов-оберток. Эти процессы находятся в режиме ожидания и используются только в момент обработки динамики.

Пример скрипта-обертки:

#!/bin/sh

# Кол-во запросов для одного процесса.
PHP_FCGI_MAX_REQUESTS=10000
export PHP_FCGI_MAX_REQUESTS

# Запуск интерпретатора.
exec /usr/bin/php-cgi

За счет разделения статики и динамики этот режим создает меньшую нагрузку на оперативную память и позволяет быстрее отдавать статику, чем mod_php. Использование opcache также возможно. Минус тот же: разделение пользователей процессов и доступов + некоторая сложность оптимальной настройки. Тем не менее, FastCGI в чистом виде почти не используется в наши дни, потому что существует более оптимальный php-fpm.

PHP FPM

Менеджер процессов php - это служба, которая создана специально для того, чтобы исполнять php код и отдавать результат серверу через интерфейс FastCGI. Он полностью берет на себя заботу на поддержку процессов, opcache и главное: запускается под отдельным пользователем! А значит веб-серверу больше не нужно тратить ресурсы на создание динамики. Его задача только обратиться к php-fpm и отдать результат пользователю.

Наиболее популярная связка на сегодня это Nginx + Php-fpm обладает высокой производительностью и позволяет отдавать статику и динамику быстро. В ней отсутствуют минусы, характерные для CGI, mod_apache и чистого FastCGI. Это режим потребляет больше памяти, однако выигрыш от его использования значителен - правильно настроенный php-fpm вместе в Nginx способен обрабатывать до 10 000 rps (запросов в секунду).

Как узнать какой режим используется?

Если вы используете хостинг или машину настраивали не вы, может потребуется время, чтобы узнать какой режим взаимодействия сервера и php используется. Самый быстрый способ это изучить phpinfo или распечатать значение константы PHP_SAPI.

Итоги

За многолетнею историю php, способов его работы и взаимодействия с сервером придумали огромное кол-во. Я рассмотрел самые основные. Многое не вошло в этот обзор по причине окончательного устаревания или, будучи новыми подходами, могло быть сложным для начинающих разработчиков (для которых создан этот сайт) и создать не нужную кашу из знаний и странных слов.

CGI - один из наиболее раритетных из оставшихся в живых. Не советую его использовать.
Apache mod_php - прост в установке и настройке. Обладает хорошей производительностью для небольших проектов.
FastCGI - почти не используется.
Php-fmp - максимально производительный и надежный. В связке с Nginx отлично справляется с нагрузкой на больших проектах.

Полезные ссылки

Все статьи

© 2020-2021 Александр Пантелеев