Typical web-application inner-architecture

Typical web-application inner-architecture

Kirill Yurkov

The First Nine Guide. Блок 3


Дисклеймер - в реальном мире архитектуры приложений крайне разнообразны, но есть достаточно универсальные слои, которые встречаются повсеместно. О них и поговорим.


В предыдущей серии мы говорили о том, как устроены рантаймы. Но рантайм сам по себе на хлеб не намажешь и сегодня попробуем понять - что нужно реализовать в выбранном нами рантайме, чтобы заслужить почетное звание веб-приложения.

Для знакомства с этим объектом я попытался найти какую-то готовую литературу, но ничего не нашел, что охватывало бы в достаточной степени веб-приложения вне зависимости от рантайма и языка.

Поэтому разработал пару своих интерпретаций, которыми хочу попробовать решить две проблемы:

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

Поехали - и ресурсы глянем и кишки посмотрим :)


Проще всего начать с понимания того через какие слои проходит HTTP запрос, для этого будем различать 4 основные слоя внутри нашего приложения:

NETWORK LAYER

Суть: превращает HTTP запрос в структурированные данные для бизнес-логики

network layer

Что тут происходит:

  •  Socket listen на порту (8080, 443)
  • Accept connections - принимаем новые подключения
  • TLS handshake - расшифровка HTTPS трафика
  • HTTP parsing - разбор заголовков и тела запроса

Часто тут думают, что это только IO-bound. Собственно на больших телах с HTTPS болеть может начать именно CPU.


REQUEST PROCESSING

Суть: превращает HTTP запрос в вызов функции и маршрутизирует к нужному обработчику

request processing

Что тут происходит:

  • Deserialize (JSON/XML/Proto) - разбор тела запроса в объекты
  • Validation & Auth - проверка токенов, прав доступа, валидация данных
  • Rate limiting - контроль частоты запросов от клиентов
  • Request routing - определение какой handler вызвать по URL

Про рейт лимиты я недавно пост делал, поэтому важно сказать, что memory-bound, это чаще всего не распределенные рейт лимиты. Распределенные будут в редисе например и это уже IO.

BUSINESS LOGIC

Суть: выполняет основную логику приложения - то ради чего существует ваш сервис

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 ответ и отправляет клиенту

response formation

Что тут происходит:

  • Serialize (JSON/XML/Proto) - превращение объектов в JSON/XML/Protobuf
  • Compression (gzip/brotli) - сжатие больших ответов для экономии трафика
  • Encryption - шифрование данных для HTTPS
  • Send to socket - отправка байтов по сети клиенту

Те же самые проблемы что и у первого слоя.

Полная картина

HTTP web-server lifecycle

Внутренняя архитектура

Теперь, когда у нас есть какое-то представление о том из каких объектов состоит типовое приложение, давайте попробуем нарисовать это в виде абстрактной архитектуры, как если бы у нас были микросервисы.

inner-architecture application


Знакомимся с объектами на схеме, их может быть и больше и меньше в реальности. Тут главное подход. Выделяем в отдельную сущность все, что имеет под собой независимый пул воркеров или любую работу, которая происходит за пределами нашего приложения.

Я выделил вот такой список:

  • HTTP Ingress - входная точка для запросов, первичная маршрутизация, load balancing между инстансами.
  • Dispatcher - распределяет запросы между воркерами, управляет очередями и приоритетами.
  • Worker Execution - основное место выполнения бизнес-логики, здесь живут контроллеры и сервисы.
  • Runtime Overhead - Garbage Collection, thread scheduling, планировщики задач. Архитектруно не очень верно говорить что компонент называется Overhead, это намеренно, чтобы подчеркнуть, что сам рантайм и его внутренние механизмы бывают сильно не бесплатны.
  • Cache Access - in-memory кеши (Caffeine, Guava), внешние кеши (Redis, Memcached).
  • Scripting & Serialization - JSON/XML/Protobuf сериализация, template engines, data transformation.
  • Logging & Instrumentation - структурированное логирование и трейсинг.
  • External Interaction - database connections, message queues, HTTP APIs и microservices.

Почему, на мой взгляд, понимание этой архитектуры важно? Рассмотрим на примере такой простой штуки как таймайут:

  • Из пула воркеров в бизнес логике делаем SQL запрос в базу данных. Представим, что у базы отдельный пул, например (мой любимый) Hikari.
  • Но пулы к базе данных заняты. Тут наш воркер тред висит и ждет, когда же там освободится уважаемая БД.
  • В данном случае у нас или начнут копится горутины или мы забьем какой-нибудь воркер пул.

Пример довольно очевидный и его, справедливости ради, можно решить наличием хорошего таймаута внутри пула к самой БД. Но чем более реактивный и эфимерный рантайм используется, тем чаще встречаю ситуации, когда даже таймаут это не так очевидно.

Мешочек с советами

Работая с внутренней архитектурой гораздо проще соблюдать паттерны отказоустойчивости:

  • таймауты и ttl на внутренних очередях
  • bulkhead и разделение пулов внутри приложения, например отдельные для CPU и IO bound (хотя это не везде возможно)
  • fallback механики, вплоть до внутренних circuit breaker

Про паттерны будет много отдельных статей.


На этом пока все!

В следующем выпуске мы закончим проектировать и писать наше идеальное приложение и пойдем его деплоить!
В предыдущей серии - разбирались с тем какие есть в мире рантаймы

Подписывайся на канал @r9yo11yp9e - будем искать девятки вместе :)





Report Page