Материал из презентации Олега Бунина, поэтому пример с https://highload.ru Внимание: такой вопрос периодически встречается на собеседованиях!
Простой вариант:
- Браузер запрашивает DNS и вычисляет IP для highload.ru;
- Браузер отправляет запрос на сервер;
- Сервер получает запрос;
- Сервер проверяет в кеше, есть ли такая страничка, если есть, то сразу к пункту 7;
- Сервер запрашивает данные из базы данных;
- Сервер строит страничку;
- Сервер отправляет страничку браузеру;
- Браузер строит страничку на экране для пользователя.
Что реально происходит:
- Браузер проверяет в локальном кэше, есть ли такая страничка;
- Если есть, то проверяет заголовки и параметры кэширования (Expires), можно ли её использовать?
- Браузер запрашивает DNS и вычисляет IP для highload.ru;
- Браузер составляет http-запрос;
- Браузер (прикладной уровень модели OSI) передаёт запрос ниже, транспортному уровню;
- Транспортный уровень сетевой подсистемы упаковывает запрос в TCP-пакеты и отправляет ещё ниже, сетевому уровню;
- Сетевой и нижележащие уровни отправляют запрос в сеть согласно таблицам маршрутизации;
- Где-то в сети потенциальные кэширующие сервера проверяют, не могут ли они выполнить этот запрос без передачи дальше по маршруту:
- Где-то в сети обрабатываются проверки блокировок от Роскомнадзора;
- TCP/IP-пакеты передаются от сервера к серверу согласно таблицам маршрутизации и, наконец, доходят до сетевого уровня целевого сервера;
- Сетевой и транспортный уровни сервера собирают запрос из пакетов;
- Проверяется, может ли порт (в данном случае 80-й) принять запрос, есть ли место в очереди, слушает ли кто-нибудь этот порт;
- Если порт слушается, то устанавливается сессия и запрос передаётся тому веб-серверу, который слушает порт;
- В нашем случае это nginx, который аллоцирует буфер для принятия запроса;
- Если буфера в памяти не хватает, то создаётся временный файл на диске;
- Дисковая подсистема операционной системы решает, где создать временный файл – в буфере или реально на диске;
- Nginx принимает весь запрос;
- Только после этого nginx проверяет, требуется ли выполнение запроса или он может обработать его без передачи бекенду (например, он в кэше или это картинка);
- Если запрос требует вычисления, то открывается upstream к бэкенду;
- Сервер, который слушает порт бэкенда открывает соединение и принимает запрос;
- В нашем случае это Apache, последовательно выполняются 11-ть стадий выполнения запроса: трансляция в URI, проверка заголовков, вычисление скрипта, который должен обработать запрос, запуск скрипта, передача скрипту информации запроса, ожидание выполнения скрипта, отдача результатов nginx’у, логгирование, этап очистки;
- Скрипт получает запрос, запускается построение страницы;
- Выполняется программа, данные с помощью SQL-запросов запрашиваются из базы данных;
- В каждом случае устанавливается соединение с базой данных (если оно не постоянное);
- База данных получает SQL-запрос;
- База данных строит план выполнения запроса, затем выполняет его, используя те или иные буферы;
- При каждом чтении таблицы сначала база данных проверяет, нет ли этой информации в кэше, затем дисковая подсистема делает тоже самое;
- Скрипт собирает данные от базы данных и вставляет их в шаблон страницы;
- Скрипт отдаёт собранную страницу веб-серверу Apache;
- Apache передаёт собранную страницу nginx;
- Nginx принимает страницу и только полностью записав её в локальный буфер начинает передачу пользователю. Всё это время соединение с пользователем открыто;
- Собранная страница в обратном порядке спускается вниз по уровням модели OSI, бьется для передачи по сети на кусочки;
- Сетевой и транспортный уровень машины пользователя собирают страницу и передают её выше;
- Браузер парсит страницу и запускает аналогичный процесс для всех её составляющих: JS-файлов, CSS-файлов, картинок. Для каждого элемента весь процесс повторяется;
- Только после получения всего этого начинается процесс построения странички для пользователя.
- PS: Браузер пытается закэшировать всё, что можно.