
В девяностых CGI сделал интернет интерактивным, но чуть не убил его. Это неудивительно, ведь каждый клик пользователя порождал новый тяжеловесный процесс на сервере. Под катом разберу, из-за чего такой подход оказался бомбой замедленного действия, и почему именно технология FastCGI спасла веб от инфраструктурного коллапса.
CGI и первые динамические сайты
В начале 1993 года, когда веб перестал быть набором статических страничек, команда NCSA опубликовала в рассылке www-talk спецификацию для вызова исполняемых файлов из командной строки. Другие разработчики тепло приняли её, и с тех пор CGI (Common Gateway Interface, не путать с computer-generated imagery) стала стандартом для веб-серверов.
Эта спецификация интерфейса позволяла веб-серверу запускать скрипт при каждом HTTP-запросе и передавать ему входные данные (например, информацию из формы), а затем возвращать пользователю ответ. Грубо говоря, это был очень простой способ оживления веб-страниц, потому что CGI-скрипты можно было писать на Perl, C, Python и даже Bash. Пример скрипта оставил ниже:
#!/usr/bin/perl print "Content-Type: text/html\n\n"; print "<html><body><h1>Hello from CGI!</h1></body></html>";
В свою очередь, веб-сервер передавал параметры запроса через переменные окружения, контент запроса — через STDIN, а скрипт выводил результат для сервера через STDOUT. Старожилы ещё, наверное, помнят папку cgi-bin на серверах в то время. В ней лежали заветные скрипты — гостевые книги на Perl, счётчики посещений и формы обратной связи.

В целом, CGI быстро стал стандартом динамического веба, так как его поддерживали все популярные веб-серверы (Apache, IIS и другие). Казалось бы, всё идеально… пока трафик не начал расти.
Курс на CGI-катастрофу
Изначально CGI-сайты были небольшими, и модель «один процесс на запрос» не вызывала никаких проблем. Но стоило нагрузке немного подрасти, проявились серьёзные недостатки.
Во-первых, каждый новый HTTP-запрос порождал внешний скриптовый процесс (из-за той самой изоляции), а по завершении он уничтожался. Если пользователи одновременно отправляли десятки запросов (а тем более сотни или тысячи), сервер прождал множество процессов.

Во-вторых, оверхед на создание процесса был огромен. Системе приходилось каждый раз загружать интерпретатор, инициализировать окружение, открывать файлы, и всё это было ради одного короткого ответа. В результате большая часть ресурсов CPU тратилась впустую на постоянный запуск/закрытие внешних программ. Неудивительно, что при высокой посещаемости CGI начинал «задыхаться».
В-третьих, CGI был неспособен к эффективному повторному использованию ресурсов. Скрипт должен обратиться к базе данных, в режиме CGI он при каждом запуске открывал новое соединение к БД, запрашивал данные и завершал работу. Следующий запрос — снова новый процесс, новое подключение к базе, а затем повторное чтение одних и тех же конфигураций. Не было никакого кэширования в памяти и никакого сохранения состояния. Программа каждый раз стартовала с нуля.

Из-за этого веб-приложения не могли держать объекты в памяти, а открытое соединение или результат предыдущих вычислений невозможно было переиспользовать. Это упрощало разработку, но больно било по производительности под нагрузкой.
В конечном счёте, к концу 90-х CGI уже не тянул высоконагруженный веб. Если сайт становился популярным, прирост трафика вызывал лавину процессов, а они, в свою очередь, забивали систему и тратили и так ограниченные ресурсы хостинга тех времён. Вот он, рецепт интернет-катастрофы — нужен был новый подход.
Первые обходные пути
Из-за того, что проблема касалась всех, несколько решений появились почти одновременно. Разработчики веб-серверов решили сделать так, чтобы код выполнялся внутри самого сервера, минуя запуск внешних процессов. Так появились проприетарные серверные API, например, NSAPI от Netscape и ISAPI от Microsoft.

Apache изначально был мультипроцессным, но CGI всё равно требовал запуска отдельной внешней программы на каждый запрос. Чтобы убрать этот оверхед, Apache тоже обзавёлся своим API для модулей — вместо того, чтобы каждый раз запускать новую программу, он позволял загружать код расширений в память сервера и вызывать его напрямую при запросах. Позднее на основе таких API появились модули вроде mod_perl и mod_php, которые фактически встраивали интерпретатор Perl или PHP прямо в процессы веб-сервера. За счёт этого скрипты выполнялись заметно быстрее.
Эта архитектура набрала популярность в начале нулевых. Достаточно было установить модуль, и можно крутить динамический сайт без внешних CGI-программ. Однако у так называемого (мной) модульного подхода были свои минусы:
утечки памяти в модулях накапливались от запроса к запросу, потому что воркер жил долго — зависший модуль мог превратить воркер в зомби-процесс, который было сложно контролировать,
зачастую модули были привязаны к языку (писались на C/C++), и код приложений должен быть потокобезопасным,
в условиях виртуального хостинга код разных пользователей выполнялся в одном пуле воркеров, что создавало угрозы безопасности — чужой скрипт мог теоретически повредить общую память или получить доступ к данным другого хоста.
Разработчикам стало тяжелее писать, а хостинг-провайдерам приходилось извращаться с SUEXEC и SUID, чтобы запускать код клиентов от разных пользователей, жертвуя выгодой производительности модулей.

Нужен был компромисс, который сохранил бы плюсы CGI (простоту и изоляцию), но убрал главный его минус — запуск процесса на каждый запрос. И такое решение появилось.
Спасение веба
В 1996 году компания Open Market предложила FastCGI. Идея разработчиков состояла в том, чтобы внешняя программа запускалась один раз и продолжала работать, обслуживая множество запросов подряд. То есть вместо того, чтобы «убивать» процесс после каждой страницы, его держали живым и переиспользовали.

Интересно, что изначально FastCGI разрабатывался как открытое расширение CGI, устраняющее узкое место с производительностью без отказа от самой модели взаимодействия. Но после стал отдельным протоколом.
В отличие от CGI, нужный FastCGI-процесс запускается при старте веб-сервера или при первом запросе. Веб-сервер вместо прямого запуска программы устанавливает с ней соединение (через Unix-сокет или TCP) и передаёт данные запроса в уже запущенный процесс. FastCGI-процесс получает запрос, обрабатывает его и затем возвращается в режим ожидания следующего запроса.
Один и тот же процесс может последовательно обработать сотни и тысячи запросов, порождая новые процессы лишь для параллельности или резервирования. Так устраняется главная проблема CGI — все инициализации (загрузка интерпретатора, подключение к базе, чтение конфигов) происходят один раз при старте FastCGI-пула.

FastCGI в буквальном смысле сохранил архитектуру «процесс вне сервера», но сделал её долгоживущей. Это дало сразу несколько преимуществ:
произошёл скачок в производительности — CGI-скрипт упирался в 5–10 запросов в секунду, а FastCGI на момент создания уже выдавал десятки и сотни,
сохранилась независимость языка — FastCGI-приложение может быть написано на любом языке, поддерживающем сокеты (таких подавляющее большинство),
осталась изоляция процессов — отдельный процесс, падение или утечка памяти в нём не приведут к падению веб-сервера и не затронут другие приложения,
появилась гибкость в развёртывании и горизонтальное масштабирование — FastCGI-процессы могут работать не только на той же машине, что и веб-сервер, но и на внешних серверах через TCP/IP.
Стоит отметить, что безопасность и изоляция с FastCGI относительно mod_php et al тоже улучшились. Поскольку FastCGI-демоны запускаются вне веб-сервера, их можно запускать от имени разных системных пользователей, ограничивать chroot-джейлами и прочими методами. Например, хостинг-провайдеры получили возможность запускать PHP-пулы для каждого пользователя отдельно, изолируя сайты друг от друга. При этом дикая просадка, которая была бы при CGI, тут не появляется.

Конечно, за всё приходится платить. Долгоживущие FastCGI-процессы означают, что в памяти в ожидании запросов постоянно висит рабочий пул, увеличивая базовое потребление памяти. Например, пул из десяти FastCGI-процессов может потреблять сотни мегабайт RAM, даже когда трафика почти нет. К слову, CGI же ничего не ел в простое, ведь процессы просто отсутствовали.
Ещё разработчикам нужно было переписывать или адаптировать свой код для таких процессов. Приходилось исправлять утечки памяти и учитывать глобальные состояния, которые при CGI-сценарии сбрасывались после каждого запуска. Но для проектов с большой нагрузкой выбор был очевиден — лучше выделить лишние 200 мегабайт памяти, чем бесполезно тратить половину мощности процессора на постоянные запуски и завершения процессов.

Спустя годы технология FastCGI незаметно вошла во многие архитектуры. Особо заметно её влияние на примере PHP-хостинга. Сначала PHP работал как модуль Apache (mod_php) или через CGI. Когда нагрузка становилась большой, mod_php на Apache начинал буксовать, поэтому в 2008–2010 годах многие крупные проекты в Рунете перешли на связку Nginx + PHP-FPM (это, по сути, и есть FastCGI-пул для PHP). На Хабре до сих пор можно найти истории тех лет о том, как переход с Apache на FastCGI давал заметный прирост производительности.
Аналогичные решения появились практически во всех экосистемах. Даже приложения на Python работают через WSGI-совместимые серверы (gunicorn, uWSGI) — архитектурно это очень похоже на FastCGI, только протокол другой.
Куда делся CGI, и при чём тут FastCGI сегодня
CGI проиграл битву за высоконагруженный веб. Как только появилась возможность избежать создания процесса на каждый запрос, практически все крупные проекты начали уходить — кто на FastCGI, кто на встроенные интерпретаторы вроде mod_php.
Сегодня трудно встретить серьёзный веб-сайт, который бы генерировался настоящими CGI-скриптами, запускаемыми при каждом обращении. Если только это не какой-то legacy-скрипт или очень небольшой внутренний инструмент, где производительность не критична.

Однако нельзя сказать, что CGI мёртв, так как его наследие живёт повсюду. Кроме того, популярные веб-серверы до сих пор поддерживают запуск CGI-скриптов на случай простых сценариев.
Да и в Unix-мире сама модель «для каждого запроса отдельный процесс» никуда не делась и не денется. Интересно, что в эпоху FaaS главная идея CGI возродилась в новом виде — в облаке изолированный контейнер для обработки события поднимается, выполняется и утилизируется. Только происходит это теперь в масштабах ЦОД и куда эффективнее, чем CGI на одном сервере.

В обычной же веб-разработке CGI сегодня — редкость. Большинство языков либо работают через постоянные процессы, либо вообще сами являются постоянными сервисами. Например, приложению на Node.js или Java не нужен отдельный веб-сервер — оно само слушает порт и работает постоянно. То есть подход, противоположный CGI, окончательно победил.
В свою очередь, FastCGI сегодня практически повсюду — он работает под капотом nginx, обслуживает PHP-пулы и крутит бэкенды — просто его мало кто замечает. А ведь без него и решений, которые пошли тем же путём, современные веб-сервисы появились бы значительно позже. Или не появились бы вовсе, потому что при первом же всплеске трафика веб бы просто «захлебнулся» пятисотыми ошибками.
Если у вас в продакшене где-то до сих пор крутится CGI-скрипт на Perl, не стесняйтесь, расскажите в комментариях. Тут не осуждают…
© 2026 ООО «МТ ФИНАНС»
Комментарии (14)

Oangai
17.03.2026 13:14извините, но у Вас фактологическая ошибка в отношении изоляции процессов - как минимум апач с самого начала реализовывал мультипроцессную модель и предлагал её по дефолту, создавался пулл дочерних процессов для обработки всех запросов где мастер только принимал и делегировал. В случае ошибки падал только один из дочерних, остальных это не касалось, мастер отслеживал пулл и восстанавливал по необходимости, так что обработчики были вполне между собой изолированы. Да и chroot для дочек там был года с 97-го как минимум. Проблемой становились как раз не падения а возможные зависания дочерних обработчиков, могли возникать зомби которых мастер уже не мог контроллировать, приходилось чуть не вручную отслеживать. Но mod_php например достаточно хорошо тестировался и зависаний не допускал, этим страдали скорее всякие самописные модули на C или mod_perl

ste4lthy24
17.03.2026 13:14mod_perl тоже просто падает обычно. не сталкивался с зависаниями, хотя, наверное возможно всё.

SrvTrantor Автор
17.03.2026 13:14Спасибо за уточнение, поправил. Я хотел подчеркнуть тот момент, что при переходе от CGI к mod_php/mod_perl изменилась сама модель, но и она была неидеальна.

beerware
17.03.2026 13:14Посмотрел на счетчики, воспоминания... первый хостинг на Караване, fortunecity.com

akakoychenko
17.03.2026 13:14Вообще, не раз ловил себя на мысли о том, что, как будто бы, сама парадигма обработки веб запросов, когда разработчик пишет код, который обрабатывает 1 запрос в вакууме, изначально ущербна.
Высокопроизводительные системы, начиная от биржевых роботов, и заканчивая субд тарантул, работают в парадигме буффера и батчевой обработки. Когда бизнес логика не процессит каждый запрос в вакууме, а делает "рейс" за батчем (там есть нюансы, как именно батчевать, но это не важно для сути), и оперирует именно батчем. Это сразу делает ряд "вебных" вызовов вообще бессмысленными. К примеру, запросить что-то вроде
select * from users where id in (10000 ids)
у реляционной СУБД и сделать 10к "разовых" запросов - принципиально разные по нагрузке и требованию к железу задачи (для модифицирующих запросов все ещё жестче).
Лично я вообще прошёл необычный путь, написав свой первый обработчик http запроса, имея годы опыта написания биржевых роботов, где миллисекунда задержки уже вечность. Из-за этого, познакомившись с веб разработкой, долго не мог понять "а как и почему мир решил жить именно так"

Kahelman
17.03.2026 13:14Не подскажете в какие годы и на каких биржах у вас миллисекунда задержки была вечностью?

lazyest
17.03.2026 13:14писал когда-то систему управления офисным сервером на REXX под OS/2 :) аккурат CGI

Kahelman
17.03.2026 13:14Сей час другая крайность «CGI” либо выпилили из новых версий серверов, либо не завозили.
Так что теперь для простой автоматизации приходится огород городить вместо того чтобы по url простой скрипт дернуть. :(

AndrewSu
17.03.2026 13:14произошёл скачок в производительности — CGI-скрипт упирался в 5–10 запросов в секунду, а FastCGI на момент создания уже выдавал десятки и сотни
Сейчас не так всё страшно.
Недавно столкнулся с необходимостью перенести свой сервис под apache2+cgi. Тестовый ендпоинд, который соединяется с БД и выполняет запрос "SELECT 1" показал 3000 RPS. Для сравнения, на том же железе с кастомным сервером и наличии пула соединений с БД было 30000 RPS на аналогичном ендпоинте.
Но если учесть, что реальные запросы "немного" сложнее, то оверхед из-за перезапуска cgi процесса не так уж сильно влияет.
Javian
Открывал прошивку ip камеры - там папка cgi есть.
pae174
Вопрос в том, что там лежит (там может быть вообще пусто) и в какой момент времени оно там запускается (может быть там скрипт для изменения настроек камеры, который вызывается один раз во время первоначальной настройки и потом не трогается больше вообще никогда).