Typical web-application inner architecture¶
The First Nine Guide. Блок 3

Дисклеймер - в реальном мире архитектуры приложений крайне разнообразны, но есть универсальные слои, которые встречаются почти везде. О них и поговорим.
В предыдущей серии мы говорили о том, как устроены рантаймы. Но рантайм сам по себе на хлеб не намажешь. Сегодня попробуем понять, что нужно реализовать в выбранном рантайме, чтобы заслужить звание веб-приложения.
Я пытался найти готовую литературу, которая бы объясняла веб-приложения независимо от рантайма и языка, но не нашел. Поэтому собрал свою интерпретацию, чтобы решить две проблемы:
- Многие инженеры не хотят погружаться в глубины работы приложения: кажется, что это невероятно сложно или непонятно с чего начать.
- Встречается и обратное - слишком упрощенный взгляд: "есть коробочка, вход, выход и бизнес-логика посередине". Это размывает понимание того, какой ресурс потребляет та или иная функция.
Поехали - посмотрим и ресурсы, и кишки.
Слои HTTP-запроса¶
Начнем с понимания того, через какие слои проходит HTTP-запрос. Для простоты выделим 4 слоя внутри приложения.
NETWORK LAYER¶
Суть: превращает HTTP-запрос в структурированные данные для бизнес-логики.

Что тут происходит:
- socket listen на порту (8080, 443)
- accept connections - принимаем новые подключения
- TLS handshake - расшифровка HTTPS трафика
- HTTP parsing - разбор заголовков и тела запроса
Часто тут думают, что это только IO-bound. На больших телах с HTTPS CPU тоже начинает болеть.
REQUEST PROCESSING¶
Суть: превращает HTTP-запрос в вызов функции и маршрутизирует к нужному обработчику.

Что тут происходит:
- deserialize (JSON/XML/Proto) - разбор тела запроса в объекты
- validation & auth - проверка токенов, прав доступа, валидация данных
- rate limiting - контроль частоты запросов
- request routing - определение handler по URL
Про рейты важно сказать: memory-bound - это чаще локальные лимиты. Распределенные лимиты обычно в Redis и это уже IO.
BUSINESS LOGIC¶
Суть: выполняет основную логику приложения - то, ради чего существует сервис.

Что тут происходит:
- domain operations - основные алгоритмы и бизнес-правила
- calculations - вычисления и обработка данных
- external API calls - обращения к сторонним сервисам
- database queries - запросы к PostgreSQL/MySQL/MongoDB
- cache operations - чтение/запись Redis/Memcached
Этот слой получает приз SRE симпатий как самый проблемный. Тут и медленные SQL, и блокировки, и внешние API без таймаутов, и тяжелые вычисления O(n!).
RESPONSE FORMATION¶
Суть: упаковывает результат обратно в HTTP-ответ и отправляет клиенту.

Что тут происходит:
- сериализация (JSON/XML/Proto)
- compression (gzip/brotli) - сжатие больших ответов
- encryption - шифрование для HTTPS
- send to socket - отправка байтов по сети
Проблемы те же, что и у первого слоя.
Полная картина¶

Внутренняя архитектура¶
Теперь, когда у нас есть представление о слоях, попробуем нарисовать это как абстрактную архитектуру, будто у нас микросервисы.

Знакомимся с объектами. Их может быть больше или меньше в реальности. Тут главное подход: выносим в отдельную сущность все, что имеет независимый пул воркеров или любую работу за пределами приложения.
Список:
- HTTP Ingress - входная точка, первичная маршрутизация, load balancing между инстансами.
- Dispatcher - распределяет запросы между воркерами, управляет очередями и приоритетами.
- Worker Execution - место выполнения бизнес-логики, контроллеры и сервисы.
- Runtime Overhead - GC, планировщики, thread scheduling. Название нарочито жесткое, чтобы подчеркнуть цену рантайма.
- Cache Access - in-memory кеши и внешние кеши (Redis/Memcached).
- Scripting & Serialization - JSON/XML/Protobuf сериализация, template engines, трансформации данных.
- Logging & Instrumentation - структурированное логирование и трейсинг.
- External Interaction - базы, очереди, HTTP API, микросервисы.
Почему это важно? Простой пример с таймаутами:
- В бизнес-логике делаем SQL-запрос в БД. У базы свой пул, например Hikari.
- Пулы к БД заняты, воркер висит и ждет, когда освободится подключение.
- В итоге копятся горутины или забивается пул воркеров.
Да, это решается таймаутом в пуле, но чем более реактивный рантайм, тем чаще это упускают.
Мешочек с советами¶
Работая с внутренней архитектурой, проще соблюдать паттерны отказоустойчивости:
- таймауты и TTL на внутренних очередях
- bulkhead и разделение пулов внутри приложения (например, отдельные для CPU и IO)
- fallback механики, вплоть до внутренних circuit breaker
Про паттерны будет много отдельных статей.
На этом пока все.
В следующем выпуске мы закончим проектировать идеальное приложение и пойдем его деплоить.
В предыдущей серии - разбирались с тем, какие есть модели рантайма.
Подписывайся на канал @r9yo11yp9e - будем искать девятки вместе.