DEV Community

faangmaster
faangmaster

Posted on

Некоторые подходы к архитектуре приложений в Amazon

Amazon использует SOA (Service-oriented Architecture) подход к архитектуре приложений. Бэкенд Amazon состоит из огромного числа сервисов/компонент, каждая из который реализует ту или иную бизнес функцию. Эти сервисы разрабатываются и поддерживаются отдельными Two-Pizza Teams. Каждая компонента живет в своем отдельном репозитории и имеет свой отдельный pipeline для деплоймента в продакшн. Каждый такой деплоймент пайплайн имеет несколько этапов:

  • Компиляция и прогон unit тестов
  • деплоймент на тестовый сервер и прогон интеграционных и performance тестов
  • Деплоймент на один из продакш серверов, автоматический мониторинг ключевых метрик с автоматическим ролбэком, в случае обнаружения проблем
  • Волны деплоймента. После мониторинг на одном сервере, деплоймент на 5, 10, 100, 1000, 10000 серверов и т.д.
  • Продакшен сервера находятся в auto-scaling группах, которые позволяют добавлять или убавлять сервера автоматически в зависимости от нагрузки.

В Amazon используется CI/CD и каждый commit сразу идет в продакшен. Время между коммитом и деплойментом в прод - несколько часов.

Скорость разработки, а также минимализация багов и скорость решения продакшен проблем очень важны в Amazon. Для этого Amazon широко использует, уже разработанные внутри компании, инфраструктурные компоненты, в том числе и доступные всем желающим - AWS. Но также есть огромное число чисто внутренних решений, которые пока не доступны в виде managed сервиса на AWS.
Эти кирпичики можно использовать, как конструктор Lego для быстрого создания масштабируемых компонент.
Вот лишь небольшая часть use case'ов, которые часто используются при разработке.

Мониторинг

Image description

Все компоненты производят метрики, которые эмитятся во внутренний мониторинг сервис. Он позволяет строить графики, производить анализ, делать дашборды, создавать алармы, автоматически создавать таски/тикеты, если какие-то метрики ведут себя не так как ожидается и многое другое. Это очень помогает делать более безопасный релиз новой функциональности, а также мониторить компоненты в продакшене и быстро находить причину проблемы. Метрики могут быть число техническими, вроде метрик производительности, так и чисто бизнес метрики.
Кроме внутреннего серсива для мониторинга, также широко используется доступный всем AWS Cloudwatch:

Image description

Иногда, таски создаются напрямую из кода компоненты. Если вывалилось какое-то критическое исключение, то прямо из catch-stement вызывается API, которое создает новую таску или дополняет ее новым стектрейсом, если такая же таска уже была создана ранее (чтобы не создать тысячи тасков с одной и той же проблемой):

try {
   ....
} catch (SomeCriticalException e) {
    taskAPI.createTask(e);
}
Enter fullscreen mode Exit fullscreen mode

Image description

Иногда, для более детального анализа, репортится большое число бизнес данных. Эти данные могут использоваться для анализа или для работы бизнес логики других компонент. Такие данные обычно отправляются в очередь типа AWS SQS, из которой периодически данные считываются и дампятся в SQL таблицу (Data Warehouse). Для визуализации могут использоваться тулы типа AWS Quicksight:

Image description

В качестве Data Warehouse обычно используется Amazon Redshift. Вместо кастомный джобы, которая читает из SQS еще используют стрим типа Kinesis:

Image description

Иногда используется Elasticsearch для анализа метрик и логов. Возможная архитектура в AWS: логи попадают в stream (Например AWS Kinesis или Kafka), оттуда в Elasticsearch и анализируется в Kibana:

Image description
Elasticsearch также позволяет сетапить алармы и по ним создавать тикеты.

Межкомпонентное взаимодействие

Чаще всего, для вызова другой компоненты в Amazon используется RPC. Для этого там есть свой внутренний framework/library:

Image description

Каждый вызов обернут в кучу слоев для достижения Resilience:

  • Retry Strategy. Если вызов компоненты закончился ошибкой, то можно попробовать вызвать сервис еще раз через некоторое время, а не возвращать ошибку в качестве результата. Но делать это нужно только для временных ошибок (transient exceptions), вроде ошибки сети и т.д. Чтобы не получить Retry Storm. Также можно увеличивать время между попытками (Exponential backoff), чтобы не перегрузить сервер если на нем большая нагрузка.
  • Circuit Breaker. Если большой процент вызовов компоненты заканчивается ошибкой, то можно перестать его вызывать до тех пор, пока сервис не восстановится.
  • Cache. Можно использовать локальный кэш (Например, Google Guava Cache) или внешний кэш (AWS ElastiCache), для того, чтобы временно кэшировать результат вызова, чтобы не перегружать внешний сервис вызовами с одними и теми же параметрами.
  • Throttling/Rate Limiting. Если число вызовов в единицу времени превышает определенный порог, то можно бросать ошибку, чтобы не перегружать сервис. В таком случае, на стороне клиента будет видно большое число throttling exceptions и нужно увеличивать квоту/добавлять сервера, чтобы поддержать увеличенный трафик. А также Retry Strategy или Cirsuit Breaker смогут временно уменьшить нагрузку на сервис.

Image description

Если нам не нужно процессить все в режиме реального времени, а нужна асинхронная обработка данных, то используются очередь. В Amazon это чаще всего AWS SQS. Одна компонента пишет в очередь, а другая читает:

Image description
Иногда, нам нужно поддержать множество consumers одних и тех же данных. Тогда можно использовать AWS SNS. Это pub-sub сервис. Одна компонента (publisher) будет отправлять нотификации в топик в AWS SNS, а другие компоненты (consumers) могут подписаться на этот топик и слушать его.
Для асинхронной обработки, можно подписать множество SQS очередей для каждого клиента. Когда каждый клиент сможет получать теже данные, что и другие клиенты:

Image description

Еще один расспространенный паттерн - это когда компоненты напрямую не взаимодействуют, но могут асинхронно использовать данные, производимые другой компонентой.

Image description
Для быстрого доступа, данные помещаются в NoSQL базу (AWS Dynamo DB).
Исходные данные, обычно, находятся в Data Warehouse (например, Amazon Redshift).

Это далеко не все паттерны, которые часто используются в создании компонент в Amazon, но одни из самых расспространенных.

Top comments (0)