В эпоху, когда современные веб-технологии развиваются с огромной скоростью, кажется, что классические методы создания динамических сайтов безнадёжно устарели. Однако не так давно CGI (Common Gateway Interface) был основным способом взаимодействия веб-сервера с программами, позволяя создавать интерактивные сайты. Несмотря на появление новых, более производительных технологий, CGI демонстрирует удивительную работоспособность даже в условиях экстремальной нагрузки на современном оборудовании. Исторически CGI-программы активно использовались в 1990-х и начале 2000-х годов для создания динамического контента. Обычно эти программы писались на Perl или даже на Си с целью повысить производительность.
Основной принцип работы заключался в следующем: когда сервер получал запрос с сайта, например, к сценарию guestbook.cgi, он создавал специальную среду с переменными окружения, содержащими информацию о запросе, и запускал отдельный процесс программы. Таким образом, каждый веб-запрос обрабатывался независимым экземпляром CGI-программы, которая использовала стандартный ввод и вывод для получения данных и отправки ответа. Важно отметить, что такой подход обладает определёнными преимуществами. Поскольку каждый CGI-процесс завершается по окончании обработки запроса, система автоматически освобождает использованную память и ресурсы.
Это позволяет избежать накопления ошибок и утечек памяти — частых проблем в длительно работающих сервисах. Кроме того, развернуть новое программное обеспечение на CGI-сервере можно было очень быстро, просто поместив обновлённые файлы в нужную директорию. С другой стороны, CGI-веб-серверы того времени, как правило, оснащались ограниченным числом процессоров и обладали всего несколькими гигабайтами памяти. Например, на классическом Apache-фреймворке с fork-моделью запускался отдельный процесс на каждое соединение, что быстро высаживало ресурсы и ограничивало число параллельных запросов. Это приводило к так называемому «обнимашечному» эффекту — когда на сайт обрушивался внезапный поток посетителей с популярного ресурса, сервер не справлялся с нагрузкой и падал.
Современное вычислительное оборудование кардинально изменило возможности работы CGI. Сегодня сервера с сотнями потоков процессоров и габаритной оперативной памятью – это уже стандарт. Даже виртуальные машины с 16-32 CPU доступны по разумной цене. Программа, построенная по принципу CGI, запускается в отдельном процессе, что позволяет эффективно использовать многопоточность и многопроцессорность современных CPU, масштабируя сервер по вертикали без существенной модернизации кода. Проведённые недавно тесты показали, что CGI-программа, работающая на 16-поточном процессоре AMD Ryzen 3700X, способна обрабатывать свыше 2400 запросов в секунду.
В пересчёте на сутки это более 200 миллионов HTTP-запросов, что является впечатляющим результатом как для такой простой архитектуры, так и для устаревшей технологии. В качестве примера была разработана гостевая книга на языке Go с базой данных SQLite. Выбор именно этих технологий дал баланс между простотой и производительностью. Гостевая книга позволяла пользователям оставлять комментарии и просматривать последние записи, при этом осуществляя записи и чтения из СУБД, что демонстрировало реальную нагрузку на серверную часть при полноценном взаимодействии с пользователем. Одна из ключевых особенностей использованного решения – включение современных оптимизаций работы с SQLite, таких как WAL-журнал и низкий уровень синхронизации, что значительно улучшает скорость записи в базу при высокой конкуренции.
Также была ограничена максимальная активная сессия к СУБД, чтобы избежать излишнего числа одновременных блокировок, что свойственно многопроцессным системам. Тестирование нагрузки методом проведения одновременных запросов (с помощью утилиты plow) подтвердила, что даже при использовании CGI, у которого изначально существует накладная на запуск процесса, можно выдерживать высокую RPS (requests per second). При этом задержки оставались низкими, большинство запросов обрабатывалось менее чем за 10 миллисекунд, что удовлетворяет требованиям многих продвинутых сервисов. Сравнение архитектуры с использованием классического Apache и с кастомным сервером на Go также показало интересные результаты. Оба варианта продемонстрировали высокую производительность, однако Go-сервер оказался чуть более эффективным в обработке запросов, что может быть связано с более лёгкой внутренней реализацией и меньшим накладным временем на системные вызовы.
В свою очередь, CGI-программы прекрасно сочетаются с современными контейнеризационными технологиями и CI/CD процессами. Образы Docker с готовыми CGI-приложениями позволяют быстро масштабировать систему в кластере и эффективно использовать ресурсы, при этом упрощая процесс деплоя и тестирования. Несмотря на все достоинства, CGI не рекомендуется для новых проектов с высокой нагрузкой, так как современные архитектуры и протоколы (например, FastCGI, WSGI или Node.js с асинхронным подходом) зачастую обеспечивают лучшую масштабируемость и удобство поддержки. Однако если уже есть существующее CGI-приложение, возможностей современного оборудования и грамотной настройки достаточно, чтобы поддерживать чрезвычайно высокий трафик без крупной переработки.