Поделиться через


Шаблон современного веб-приложения для .NET

Служба приложений Azure
Azure Front Door
Кэш Azure для Redis
.NET

В этой статье показано, как реализовать шаблон современного веб-приложения. Шаблон современного веб-приложения определяет, как модернизировать веб-приложения в облаке и представить архитектуру, ориентированную на обслуживание. Шаблон современного веб-приложения предоставляет предписную архитектуру, код и рекомендации по настройке, которые соответствуют принципам Azure Well-Architected Framework и построению на основе шаблона Reliable Web App.

Почему используйте шаблон современного веб-приложения?

Шаблон современного веб-приложения поможет оптимизировать области веб-приложения с высоким спросом. В ней приведены подробные рекомендации по расшифровкам этих областей, что позволяет независимо масштабироваться для оптимизации затрат. Этот подход позволяет выделить выделенные ресурсы критически важным компонентам, что повышает общую производительность. Разреженные службы могут повысить надежность, предотвращая замедление в одной части приложения от влияния на других пользователей. Распаковка также позволяет самостоятельно версии отдельных компонентов приложений.

Реализация шаблона современного веб-приложения

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

  • Руководство по архитектуре. Узнайте, как модульизировать компоненты веб-приложения и выбрать соответствующую платформу в качестве службы (PaaS).
  • Руководство по коду. Реализуйте четыре шаблона проектирования для оптимизации разделенных компонентов: Strangler Fig, Queue-Based выравнивание нагрузки, конкурирующих потребителей и мониторинг конечных точек работоспособности.
  • Руководство по настройке. Настройте проверку подлинности, авторизацию, автомасштабирование и контейнеризацию для компонентов, разделенных.

Совет

Логотип GitHub Существует эталонная реализация (пример приложения) шаблона современного веб-приложения. Он представляет конечное состояние реализации современного веб-приложения. Это рабочее веб-приложение, которое содержит все обновления кода, архитектуры и конфигурации, рассмотренные в этой статье. Развертывание и использование эталонной реализации для реализации шаблона современного веб-приложения.

Руководство по архитектуре

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

схема, показывающая базовую архитектуру шаблона современного веб-приложения.

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

Схема, показывающая архитектуру шаблона современного веб-приложения со второй областью и топологией сети концентратора и периферийной сети.

Разделение архитектуры

Чтобы реализовать шаблон современного веб-приложения, необходимо разделить существующую архитектуру веб-приложения. Разбиение архитектуры включает разбиение монолитного приложения на небольшие независимые службы, которые отвечают за определенную функцию или функциональные возможности. Этот процесс подразумевает оценку текущего веб-приложения, изменение архитектуры и, наконец, извлечение кода веб-приложения на платформу контейнеров. Цель заключается в систематическом определении и извлечении служб приложений, которые пользуются наибольшим преимуществом от разложения. Чтобы разделить архитектуру, следуйте приведенным ниже рекомендациям.

  • Определите границы служб. Примените принципы проектирования на основе домена, чтобы определить ограниченные контексты в монолитном приложении. Каждый ограниченный контекст представляет логическую границу и может быть кандидатом на отдельную службу. Службы, представляющие различные бизнес-функции и имеющие меньше зависимостей, являются хорошими кандидатами на развязку.

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

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

  • Развертывание служб Azure. Выберите и разверните службы Azure, необходимые для поддержки службы веб-приложений, которую вы планируете извлечь. Инструкции см. в разделе "Выбор правильных служб Azure".

  • Отделять службы веб-приложений. Определите четкие интерфейсы и API, чтобы новые извлеченные службы веб-приложений могли взаимодействовать с другими частями системы. Разработка стратегии управления данными, которая позволяет каждой службе управлять собственными данными, обеспечивая согласованность и целостность. Сведения о конкретных стратегиях реализации и шаблонах проектирования, используемых во время этого процесса извлечения, см. в разделе "Руководство по коду " этой статьи.

  • Используйте независимое хранилище для отдельных служб. Каждая отделенная служба должна иметь собственное изолированное хранилище данных, чтобы упростить независимое управление версиями, развертывание и масштабируемость и обеспечить целостность данных. Например, эталонная реализация отделяет службу отрисовки билетов от веб-API и устраняет необходимость в службе доступа к базе данных API. Вместо этого служба передает URL-адрес, в котором образы билетов были созданы обратно в веб-API с помощью сообщения служебной шины Azure, а API сохраняет путь к базе данных.

  • Реализуйте отдельные конвейеры развертывания для каждой отдельной службы. Отдельные конвейеры развертывания позволяют обновлять каждую службу по своему темпу. Если разные команды или организации в вашей компании имеют разные службы, то отдельные конвейеры развертывания предоставляют каждому команду контроль над собственными развертываниями. Используйте средства непрерывной интеграции и непрерывной доставки (CI/CD), такие как Jenkins, GitHub Actions или Azure Pipelines для настройки этих конвейеров.

  • Изменение элементов управления безопасностью. Убедитесь, что элементы управления безопасностью обновлены для учетной записи новой архитектуры, включая правила брандмауэра и элементы управления доступом.

Выберите нужные службы Azure

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

  • Выберите очередь сообщений. Очередь сообщений является важным компонентом архитектуры, ориентированной на обслуживание. Он отделяет отправителей сообщений и получателей для включения асинхронного обмена сообщениями. Используйте рекомендации по выбору службы обмена сообщениями Azure, чтобы выбрать систему обмена сообщениями Azure, которая поддерживает ваши потребности в проектировании. В Azure есть три службы обмена сообщениями: Сетка событий Azure, Центры событий Azure и служебная шина Azure. Начните с служебная шина в качестве варианта по умолчанию и используйте другие два варианта, если служебная шина не соответствует вашим потребностям.

    Service Вариант использования
    Cлужебная шина Выберите служебная шина для надежной, упорядоченной и, возможно, транзакционной доставки сообщений с высоким уровнем ценности в корпоративных приложениях.
    Сетка событий Выберите сетку событий, когда необходимо эффективно обрабатывать большое количество дискретных событий. Сетка событий масштабируема для приложений, управляемых событиями, где многие небольшие независимые события (например, изменения состояния ресурсов) должны направляться подписчикам в модели публикации публикации с низкой задержкой.
    Event Hubs Выберите Центры событий для массового приема данных с высокой пропускной способностью, например телеметрии, журналов или аналитики в режиме реального времени. Центры событий оптимизированы для сценариев потоковой передачи, в которых массовые данные должны обрабатываться и обрабатываться непрерывно.
  • Реализуйте службу контейнеров. Для компонентов приложения, которые требуется контейнеризировать, требуется платформа приложений, поддерживающая контейнеры. Руководство по выбору службы контейнеров Azure поможет вам принять решение. В Azure есть три основных службы контейнеров: приложения контейнеров Azure, Служба Azure Kubernetes (AKS) и служба приложение Azure. Начните с контейнерных приложений в качестве варианта по умолчанию и используйте другие два варианта, если контейнерные приложения не соответствуют вашим потребностям.

    Service Вариант использования
    Контейнеры приложений Выберите контейнерные приложения, если вам нужна бессерверная платформа, которая автоматически масштабирует контейнеры и управляет контейнерами в приложениях на основе событий.
    AKS Выберите AKS, если вам нужен подробный контроль над конфигурациями Kubernetes и расширенными функциями масштабирования, сети и безопасности.
    Веб-приложения для контейнеров Выберите веб-приложение для контейнеров в службе приложений для простого интерфейса PaaS.
  • Реализуйте репозиторий контейнеров. При использовании любой вычислительной службы на основе контейнеров необходимо иметь репозиторий для хранения образов контейнеров. Вы можете использовать общедоступный реестр контейнеров, например Docker Hub или управляемый реестр, например Реестр контейнеров Azure. Общие сведения о реестрах контейнеров в Azure помогут вам принять решение.

Руководство по коду

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

Схема, показывающая роли шаблонов проектирования в архитектуре шаблона современного веб-приложения.

  1. Шаблон Strangler Fig: шаблон Strangler Fig добавочно переносит функциональные возможности из монолитного приложения в службу, разделенную. Реализуйте этот шаблон в основном веб-приложении для постепенной миграции функций в независимые службы путем направления трафика на основе конечных точек.

  2. Шаблон выравнивания нагрузки на основе очередей: шаблон выравнивания нагрузки на основе очередей управляет потоком сообщений между производителем и потребителем с помощью очереди в качестве буфера. Реализуйте этот шаблон в базе кода, которая создает сообщения для очереди. Затем служба, разделенная, использует эти сообщения из очереди асинхронно.

  3. Шаблон конкурирующих потребителей: шаблон конкурирующих потребителей позволяет нескольким экземплярам развязанной службы независимо считывать из одной очереди сообщений и конкурировать с обработкой сообщений. Реализуйте этот шаблон в развязанной службе для распределения задач между несколькими экземплярами.

  4. Шаблон мониторинга конечных точек работоспособности: шаблон мониторинга конечных точек работоспособности предоставляет конечные точки для мониторинга состояния и работоспособности различных частей веб-приложения. (4a) Реализуйте этот шаблон в основном веб-приложении. (4b) Кроме того, реализуйте его в отдельной службе для отслеживания работоспособности конечных точек.

  5. Шаблон повторных попыток: шаблон повторных попыток обрабатывает временные сбои путем повторения операций, которые могут периодически завершаться ошибкой. (5a) Реализуйте этот шаблон во всех исходящих вызовах других служб Azure в основном веб-приложении, таких как вызовы очереди сообщений и частные конечные точки. (5b) Кроме того, реализуйте этот шаблон в отдельной службе для обработки временных сбоев в вызовах частных конечных точек.

Каждый шаблон проектирования предоставляет преимущества, которые соответствуют одному или нескольким компонентам платформы Well-Architected Framework. Дополнительные сведения см. в следующей таблице.

Конструктивный шаблон Расположение реализации Надежность (RE) Безопасность (SE) Оптимизация затрат (CO) Операционное превосходство (OE) Эффективность производительности (PE) Поддержка принципов хорошо спроектированной платформы
Шаблон Strangler Fig Основное веб-приложение RE:08
CO:07
CO:08
OE:06
OE:11
Шаблон балансировки нагрузки на основе очередей Основное веб-приложение (производитель сообщений) RE:07
RE:07
CO:12
PE:05
Шаблон конкурирующих потребителей Отсоединяемая служба RE:05
RE:07
CO:05
CO:07
PE:05
PE:07
Шаблон мониторинга конечных точек работоспособности Основное веб-приложение и отделяемая служба RE:07
RE:10
OE:07
PE:05
шаблон повторных попыток Основное веб-приложение и отделяемая служба RE:07

Реализация шаблона Strangler Fig

Используйте шаблон Strangler Fig для постепенной миграции функций из монолитной базы кода в новые независимые службы. Извлеките новые службы из существующей монолитной базы кода и медленно модернизируйте критически важные части веб-приложения. Чтобы реализовать шаблон Strangler Fig, следуйте приведенным ниже рекомендациям.

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

  • Управление развертыванием компонентов. Используйте библиотеки управления функциями .NET для реализации флагов компонентов и поэтапного развертывания для постепенного развертывания разложенных служб. Существующая монолитная маршрутизация приложений должна контролировать количество запросов, получаемых несвязанными службами. Начните с небольшого процента запросов и увеличение использования с течением времени, так как вы получаете уверенность в стабильности и производительности новой службы. Например, эталонная реализация извлекает функциональные возможности отрисовки билетов в автономную службу, которая может постепенно появиться для обработки большей части запросов на отрисовку билетов. Так как новая служба подтверждает свою надежность и производительность, она в конечном итоге может взять на себя всю функцию отрисовки билетов из монолита, завершив переход.

  • Используйте службу фасада (при необходимости). Служба фасада полезна, если один запрос должен взаимодействовать с несколькими службами или когда требуется скрыть сложность базовой системы от клиента. Однако если у службы, разделенной, нет общедоступных API- интерфейсов, служба фасада может не потребоваться. В базе кода монолитного веб-приложения реализуйте службу фасада для маршрутизации запросов в соответствующую серверную часть (монолит или микрослужбу). В новой отдельной службе убедитесь, что новая служба может обрабатывать запросы независимо при доступе через фасад.

Реализация шаблона выравнивания нагрузки на основе очередей

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

  • Используйте очередь сообщений без блокировки. Убедитесь, что процесс, отправляющий сообщения в очередь, не блокирует другие процессы, ожидая отсоединяемой службы для обработки сообщений в очереди. Если для процесса требуется результат операции отсоединяемой службы, можно использовать альтернативный способ обработки ситуации, ожидая завершения операции в очереди. Например, эталонная реализация использует служебная шина и await ключевое слово для messageSender.PublishAsync() асинхронной публикации сообщений в очередь без блокировки потока, выполняющего этот код:

    // Asynchronously publish a message without blocking the calling thread.
    await messageSender.PublishAsync(new TicketRenderRequestMessage(Guid.NewGuid(), ticket, null, DateTime.Now), CancellationToken.None);
    

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

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

  • Настройте идемпотентную обработку сообщений. Логика, которая обрабатывает сообщения из очереди, должна быть идемпотентной для обработки случаев, когда сообщение может обрабатываться более одного раза. Например, эталонная реализация используется ServiceBusClient.CreateProcessor и AutoCompleteMessages = trueReceiveMode = ServiceBusReceiveMode.PeekLock гарантирует, что сообщения обрабатываются только один раз и могут быть повторно обработаны при сбое. Следующий код иллюстрирует эту логику.

    // Create a processor for idempotent message processing.
    var processor = serviceBusClient.CreateProcessor(path, new ServiceBusProcessorOptions
    {
        // Allow the messages to be auto-completed
        // if processing finishes without failure.
        AutoCompleteMessages = true,
    
        // PeekLock mode provides reliability in that unsettled messages
        // will be redelivered on failure.
        ReceiveMode = ServiceBusReceiveMode.PeekLock,
    
        // Containerized processors can scale at the container level
        // and need not scale via the processor options.
        MaxConcurrentCalls = 1,
        PrefetchCount = 0
    });
    
  • Управление изменениями в интерфейсе. Асинхронная обработка может привести к тому, что задачи не выполняются немедленно. Пользователи должны знать, когда их задача по-прежнему обрабатывается, чтобы задать правильные ожидания и избежать путаницы. Используйте визуальные подсказки или сообщения, чтобы указать, что выполняется задача. Предоставьте пользователям возможность получать уведомления при выполнении задачи, например сообщение электронной почты или push-уведомление.

Реализация шаблона конкурирующих потребителей

Реализуйте шаблон конкурирующих потребителей в развязанных службах для управления входящими задачами из очереди сообщений. Этот шаблон включает распределение задач между несколькими экземплярами развязанных служб. Эти службы обрабатывают сообщения из очереди, повышая балансировку нагрузки и повышая емкость системы для обработки одновременных запросов. Шаблон конкурирующих потребителей действует в следующих случаях:

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

Чтобы реализовать шаблон конкурирующих потребителей, следуйте приведенным ниже рекомендациям.

  • Обработка параллельных сообщений. Когда система получает сообщения из очереди, убедитесь, что система предназначена для одновременного обработки нескольких сообщений. Задайте максимальное число одновременных вызовов 1, чтобы отдельный потребитель обрабатывал каждое сообщение.

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

  • Используйте режимы надежной обработки сообщений. Используйте режим надежной обработки, например PeekLock (или его эквивалент), который автоматически повторяет сообщения, которые завершаются сбоем. Этот режим обеспечивает большую надежность, чем методы удаления. Если не удается обработать сообщение, другой должен иметь возможность обрабатывать его без ошибок, даже если сообщение обрабатывается несколько раз.

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

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

  • Масштабирование на основе длины очереди. Службы, использующие сообщения из очереди, должны рассмотреть возможность автомасштабирования на основе длины очереди или использования дополнительных критериев масштабирования , чтобы лучше обрабатывать пики входящих сообщений.

  • Используйте очередь ответа на сообщение. Если системе требуются уведомления для обработки сообщений после сообщения, настройте выделенную очередь ответа или ответа. Эта настройка разделяет операционные сообщения от процессов уведомлений.

  • Используйте службы без отслеживания состояния. Рассмотрите возможность использования служб без отслеживания состояния для обработки запросов из очереди. Эти службы позволяют легко масштабировать и эффективно использовать ресурсы.

  • Настройка ведения журнала. Интегрируйте ведение журнала и обработку конкретных исключений в рабочий процесс обработки сообщений. Сосредоточьтесь на захвате ошибок сериализации и перенаправлении этих проблемных сообщений в механизм недоставленных букв. Эти журналы предоставляют ценные аналитические сведения для устранения неполадок.

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

  • AutoCompleteMessages. Автоматически завершает сообщения, если они обрабатываются без сбоя.
  • ReceiveMode. Использует режим PeekLock и повторное создание сообщений, если они не урегулированы.
  • MaxConcurrentCalls. Установите значение 1 для обработки одного сообщения одновременно.
  • PrefetchCount. Установите значение 0, чтобы избежать предварительной выборки сообщений.

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

// Create a processor for the given queue that will process
// incoming messages.
var processor = serviceBusClient.CreateProcessor(path, new ServiceBusProcessorOptions
{
    // Allow the messages to be auto-completed
    // if processing finishes without failure.
    AutoCompleteMessages = true,
    // PeekLock mode provides reliability in that unsettled messages
    // are redelivered on failure.
    ReceiveMode = ServiceBusReceiveMode.PeekLock,
    // Containerized processors can scale at the container level
    // and need not scale via the processor options.
    MaxConcurrentCalls = 1,
    PrefetchCount = 0
});

// Called for each message received by the processor.
processor.ProcessMessageAsync += async args =>
{
    logger.LogInformation("Processing message {MessageId} from {ServiceBusNamespace}/{Path}", args.Message.MessageId, args.FullyQualifiedNamespace, args.EntityPath);
    // Unhandled exceptions in the handler will be caught by
    // the processor and result in abandoning and dead-lettering the message.
    try
    {
        var message = args.Message.Body.ToObjectFromJson<T>();
        await messageHandler(message, args.CancellationToken);
        logger.LogInformation("Successfully processed message {MessageId} from {ServiceBusNamespace}/{Path}",args.Message.MessageId, args.FullyQualifiedNamespace, args.EntityPath);
    }
    catch (JsonException)
    {
        logger.LogError("Invalid message body; could not be deserialized to {Type}", typeof(T));
        await args.DeadLetterMessageAsync(args.Message, $"Invalid message body; could not be deserialized to {typeof(T)}",cancellationToken: args.CancellationToken);
    }
};

Реализация шаблона мониторинга конечной точки работоспособности

Реализуйте шаблон мониторинга конечных точек работоспособности в основном коде приложения и отсоедините код службы для отслеживания работоспособности конечных точек приложения. Оркестраторы, такие как AKS или контейнерные приложения, могут опрашивать эти конечные точки, чтобы проверить работоспособность службы и перезапустить неработоспособные экземпляры. ASP.NET приложения Core могут добавлять выделенное ПО промежуточного слоя проверки работоспособности для эффективного обслуживания данных работоспособности конечных точек и зависимостей ключей. Чтобы реализовать шаблон мониторинга конечных точек работоспособности, выполните следующие рекомендации.

  • Реализуйте проверки работоспособности. Используйте по промежуточному слоям проверки работоспособности ASP.NET Core для предоставления конечных точек проверки работоспособности.

  • Проверка зависимостей. Убедитесь, что проверка работоспособности проверяет доступность зависимостей ключей, таких как база данных, хранилище и система обмена сообщениями. Пакет, отличный от Microsoft AspNetCore.Diagnostics.HealthChecks , может реализовать проверки зависимостей проверки работоспособности для многих распространенных зависимостей приложений.

    Например, эталонная реализация использует ПО промежуточного слоя проверки работоспособности ядра ASP.NET для предоставления конечных точек проверки работоспособности. Он использует AddHealthChecks() метод для builder.Services объекта. Код проверяет доступность зависимостей ключей, хранилища BLOB-объектов Azure и очереди служебной шины с помощью AddAzureBlobStorage() методов и AddAzureServiceBusQueue() методов, которые являются частью AspNetCore.Diagnostics.HealthChecks пакета. Контейнерные приложения позволяют настраивать пробы работоспособности, отслеживаемые для оценки работоспособности приложений или необходимости повторной переработки.

    // Add health checks, including health checks for Azure services
    // that are used by this service.
    // The Blob Storage and Service Bus health checks are provided by
    // AspNetCore.Diagnostics.HealthChecks
    // (a popular open source project) rather than by Microsoft. 
    // https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks
    builder.Services.AddHealthChecks()
    .AddAzureBlobStorage(options =>
    {
        // AddAzureBlobStorage will use the BlobServiceClient registered in DI.
        // We just need to specify the container name.
        options.ContainerName = builder.Configuration.GetRequiredConfigurationValue("App:StorageAccount:Container");
    })
    .AddAzureServiceBusQueue(
        builder.Configuration.GetRequiredConfigurationValue("App:ServiceBus:Host"),
        builder.Configuration.GetRequiredConfigurationValue("App:ServiceBus:RenderRequestQueueName"),
        azureCredentials);
    
    // Further app configuration omitted for brevity.
    app.MapHealthChecks("/health");
    
  • Настройте ресурсы Azure. Настройте ресурсы Azure для использования URL-адресов проверки работоспособности приложения для подтверждения активности и готовности. Например, эталонная реализация использует Bicep для настройки URL-адресов проверки работоспособности для подтверждения активности и готовности ресурса Azure. Проба активности попадает /health в конечную точку каждые 10 секунд после начальной задержки в 2 секунды.

    probes: [
      {
        type: 'liveness'
        httpGet: {
          path: '/health'
          port: 8080
        }
        initialDelaySeconds: 2
        periodSeconds: 10
      }
    ]
    

Реализация шаблона повторных попыток

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

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

  • Используйте экспоненциальную обратную передачу. Реализуйте экспоненциальную стратегию обратного выхода для повторных попыток. Эта стратегия включает увеличение времени между каждым повтором экспоненциально, что помогает снизить нагрузку на систему в периоды высоких показателей сбоев.

  • Используйте функцию повторных попыток пакета SDK. Для служб, которые имеют специализированные пакеты SDK, такие как служебная шина или хранилище BLOB-объектов, используйте встроенные механизмы повторных попыток. Встроенные механизмы повторных попыток оптимизированы для типичных вариантов использования службы и могут более эффективно обрабатывать повторные попытки с меньшими требованиями к конфигурации. Например, эталонная реализация использует встроенные функции повторных попыток пакета SDK служебная шина (ServiceBusClientиServiceBusRetryOptions). Объект ServiceBusRetryOptions извлекает параметры из MessageBusOptions настройки параметров повторных попыток, таких как MaxRetries, и DelayMaxDelayTryTimeout.

    // ServiceBusClient is thread-safe and can be reused for the lifetime
    // of the application.
    services.AddSingleton(sp =>
    {
        var options = sp.GetRequiredService<IOptions<MessageBusOptions>>().Value;
        var clientOptions = new ServiceBusClientOptions
        {
            RetryOptions = new ServiceBusRetryOptions
            {
                Mode = ServiceBusRetryMode.Exponential,
                MaxRetries = options.MaxRetries,
                Delay = TimeSpan.FromSeconds(options.BaseDelaySecondsBetweenRetries),
                MaxDelay = TimeSpan.FromSeconds(options.MaxDelaySeconds),
                TryTimeout = TimeSpan.FromSeconds(options.TryTimeoutSeconds)
            }
        };
        return new ServiceBusClient(options.Host, azureCredential ?? new DefaultAzureCredential(), clientOptions);
    });
    
  • Внедрение стандартных библиотек устойчивости для клиентов HTTP. Для обмена данными ПО HTTP интегрируйте стандартную библиотеку устойчивости, например Polly или Microsoft.Extensions.Http.Resilience. Эти библиотеки предлагают комплексные механизмы повторных попыток, которые являются важными для управления взаимодействием с внешними веб-службами.

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

Реализация распределенной трассировки

Поскольку приложения становятся более ориентированными на обслуживание и их компоненты отделены, мониторинг потока выполнения между службами имеет решающее значение. Шаблон современного веб-приложения использует Application Insights и Azure Monitor для видимости работоспособности приложений и производительности с помощью API OpenTelemetry, которые поддерживают распределенную трассировку.

Распределенная трассировка отслеживает запрос пользователя по мере прохождения нескольких служб. При получении запроса он помечен идентификатором трассировки, который передается другим компонентам через заголовки HTTP и служебная шина свойства во время вызова зависимостей. Затем трассировки и журналы включают идентификатор трассировки и идентификатор действия (или идентификатор диапазона), соответствующий конкретному компоненту и его родительскому действию. Средства мониторинга, такие как Application Insights, используют эту информацию для отображения дерева действий и журналов в разных службах, что имеет решающее значение для мониторинга распределенных приложений.

  • Установите библиотеки OpenTelemetry. Используйте библиотеки инструментирования для включения трассировки и метрик из общих компонентов. Добавьте настраиваемое инструментирование с System.Diagnostics.ActivitySource помощью и System.Diagnostics.Activity при необходимости. Используйте библиотеки экспортеров для прослушивания диагностика OpenTelemetry и записи их в постоянных хранилищах. Используйте существующие экспортеры или создайте собственные с помощью System.Diagnostics.ActivityListener.

  • Настройка OpenTelemetry. Используйте распределение OpenTelemetry (Azure.Monitor.OpenTelemetry.AspNetCore) в Azure Monitor. Убедитесь, что она экспортирует диагностику в Application Insights и включает встроенные инструментирование для общих метрик, трассировок, журналов и исключений из среды выполнения .NET и ASP.NET Core. Включите другие пакеты инструментирования OpenTelemetry для клиентов SQL, Redis и Azure SDK.

  • Мониторинг и анализ. После настройки трассировки убедитесь, что журналы, трассировки, метрики и исключения записываются и отправляются в Application Insights. Убедитесь, что включены идентификаторы трассировки, действия и родительского действия. Эти идентификаторы позволяют Application Insights предоставлять сквозную видимость трассировки по границам HTTP и служебной шины. Используйте эту настройку для мониторинга и анализа действий приложения в разных службах.

В примере современного веб-приложения используется распределение OpenTelemetryAzure.Monitor.OpenTelemetry.AspNetCore () в Azure Monitor. Дополнительные пакеты инструментирования используются для клиентов SQL, Redis и Azure SDK. OpenTelemetry настраивается в примере службы отрисовки билетов в современном веб-приложении следующим образом:

builder.Logging.AddOpenTelemetry(o => 
{ 
    o.IncludeFormattedMessage = true; 
    o.IncludeScopes = true; 
}); 

builder.Services.AddOpenTelemetry() 
    .UseAzureMonitor(o => o.ConnectionString = appInsightsConnectionString) 
    .WithMetrics(metrics => 
    { 
        metrics.AddAspNetCoreInstrumentation() 
                .AddHttpClientInstrumentation() 
                .AddRuntimeInstrumentation(); 
    }) 
    .WithTracing(tracing => 
    { 
        tracing.AddAspNetCoreInstrumentation() 
                .AddHttpClientInstrumentation() 
                .AddSource("Azure.*"); 
    }); 

Метод builder.Logging.AddOpenTelemetry направляет все журналы через OpenTelemetry, чтобы обеспечить согласованность трассировки и ведения журнала в приложении. Так как службы OpenTelemetry зарегистрированы в builder.Services.AddOpenTelemetryслужбе , приложение настраивается для сбора и экспорта диагностики, которые затем отправляются в Application Insights через UseAzureMonitor. Кроме того, инструментирование клиентов для таких компонентов, как служебная шина и HTTP-клиенты, настраивается WithMetrics и WithTracingпозволяет автоматически выполнять сбор метрик и трассировки, не требуя изменений в существующем использовании клиента. Требуется только обновление конфигурации.

Руководство по настройке

В следующих разделах приведены рекомендации по реализации обновлений конфигурации. Каждый раздел соответствует одному или нескольким основам хорошо спроектированной платформы.

Настройка Надежность (RE) Безопасность (SE) Оптимизация затрат (CO) Операционное превосходство (OE) Эффективность производительности (PE) Поддержка принципов хорошо спроектированной платформы
Настройка проверки подлинности и авторизации SE:05
OE:10
Реализация независимого автомасштабирования RE:06
CO:12
PE:05
Развертывание службы containerize CO:13
PE:09
PE:03

Настройка проверки подлинности и авторизации

Чтобы настроить проверку подлинности и авторизацию в любых новых службах Azure (удостоверения рабочих нагрузок), которые вы добавили в веб-приложение, выполните следующие рекомендации.

  • Используйте управляемые удостоверения для каждой новой службы. Каждая независимая служба должна иметь собственное удостоверение и использовать управляемые удостоверения для проверки подлинности между службами. Управляемые удостоверения устраняют необходимость управления учетными данными в коде и снижают риск утечки учетных данных. Они помогают избежать размещения конфиденциальных данных, таких как строка подключения в файлах кода или конфигурации.

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

  • Внедрение инфраструктуры в качестве кода (IaC). Используйте средства Bicep или аналогичные средства IaC для определения облачных ресурсов и управления ими. IaC обеспечивает согласованное применение конфигураций безопасности в развертываниях и позволяет управлять версиями настройки инфраструктуры.

Чтобы настроить проверку подлинности и авторизацию для пользователей (удостоверений пользователей), выполните следующие рекомендации.

  • Предоставьте пользователям наименьшие привилегии. Как и в службах, убедитесь, что пользователи получают только разрешения, необходимые им для выполнения задач. Регулярно просматривайте и настраивайте эти разрешения.

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

Эталонная реализация использует IaC для назначения управляемых удостоверений добавленным службам и определенным ролям для каждого удостоверения. Он определяет роли и разрешения для развертывания (containerRegistryPushRoleId), владельца приложения (containerRegistryPushRoleId) и приложения контейнеров (containerRegistryPullRoleId). В следующем примере показан код.

roleAssignments: \[
    {
    principalId: deploymentSettings.principalId
    principalType: deploymentSettings.principalType
    roleDefinitionIdOrName: containerRegistryPushRoleId
    }
    {
    principalId: ownerManagedIdentity.outputs.principal_id
    principalType: 'ServicePrincipal'
    roleDefinitionIdOrName: containerRegistryPushRoleId
    }
    {
    principalId: appManagedIdentity.outputs.principal_id
    principalType: 'ServicePrincipal'
    roleDefinitionIdOrName: containerRegistryPullRoleId
    }
\]

Эталонная реализация назначает управляемое удостоверение в качестве нового удостоверения контейнерных приложений при развертывании:

module renderingServiceContainerApp 'br/public:avm/res/app/container-app:0.1.0' = {
  name: 'application-rendering-service-container-app'
  scope: resourceGroup()
  params: {
    // Other parameters omitted for brevity.
    managedIdentities: {
      userAssignedResourceIds: [
        managedIdentity.id
      ]
    }
  }
}

Настройка независимого автомасштабирования

Шаблон современного веб-приложения начинает разбиение монолитной архитектуры и представляет разбиение службы. Если вы отделяете архитектуру веб-приложения, можно масштабировать отдельные службы независимо друг от друга. Масштабирование служб Azure для поддержки независимой службы веб-приложений, а не всего веб-приложения, оптимизирует затраты на масштабирование во время удовлетворения требований. Чтобы выполнить автомасштабирование контейнеров, следуйте приведенным ниже рекомендациям.

  • Используйте службы без отслеживания состояния. Убедитесь, что службы без отслеживания состояния. Если приложение .NET содержит состояние сеанса в процессе, внешний его в распределенный кэш, например Redis или базу данных, например SQL Server.

  • Настройте правила автомасштабирования. Используйте конфигурации автомасштабирования, которые обеспечивают наиболее экономичный контроль над службами. Для контейнерных служб масштабирование на основе событий, например Kubernetes Event-Driven Autoscaler (KEDA), часто предоставляет детализированный контроль, позволяющий масштабироваться на основе метрик событий. Контейнерные приложения и AKS поддерживают KEDA. Для служб, которые не поддерживают KEDA, например Службу приложений, используйте функции автомасштабирования, предоставляемые платформой. Эти функции часто включают масштабирование на основе правил на основе метрик или ТРАФИКА HTTP.

  • Настройте минимальные реплики. Чтобы предотвратить холодный запуск, настройте параметры автомасштабирования для поддержания как минимум одной реплики. Холодный запуск возникает при инициализации службы из остановленного состояния, который часто создает отложенный ответ. Если минимизация затрат является приоритетом и вы можете терпеть задержки холодного запуска, задайте минимальное число реплик значение 0 при настройке автомасштабирования.

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

  • Настройте масштабирование на основе очередей. Если приложение использует очередь сообщений, например служебная шина, настройте параметры автомасштабирования для масштабирования на основе длины очереди с сообщениями запроса. Масштабировщик предназначен для поддержания одной реплики службы для каждого N-сообщения в очереди (округлено).

Например, эталонная реализация использует масштабировщик KEDA служебная шина для масштабирования приложения-контейнера на основе длины очереди. Служба service-bus-queue-length-rule масштабируется на основе длины указанной очереди служебная шина. Параметр messageCount имеет значение 10, поэтому масштабировщик имеет одну реплику службы для каждых 10 сообщений в очереди. scaleMaxReplicas Параметры scaleMinReplicas задают максимальное и минимальное количество реплик для службы. Секретqueue-connection-string, содержащий строка подключения для очереди служебная шина, извлекается из Azure Key Vault. Этот секрет используется для проверки подлинности масштабировщика в служебная шина.

scaleRules: [
  {
    name: 'service-bus-queue-length-rule'
    custom: {
      type: 'azure-servicebus'
      metadata: {
        messageCount: '10'
        namespace: renderRequestServiceBusNamespace
        queueName: renderRequestServiceBusQueueName
      }
      auth: [
        {
          secretRef: 'render-request-queue-connection-string'
          triggerParameter: 'connection'
        }
      ]
    }
  }
]

scaleMaxReplicas: 5
scaleMinReplicas: 0

Развертывание службы containerize

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

  • Определите границы домена. Начните с идентификации границ домена в монолитном приложении. Это помогает определить, какие части приложения можно извлечь в отдельные службы.

  • Создание образов Docker. При создании образов Docker для служб .NET используйте базовые образы. Эти образы содержат только минимальный набор пакетов, необходимых для запуска .NET, что сводит к минимуму размер пакета и область области атаки.

  • Используйте многоэтапные файлы Dockerfile. Реализуйте многоэтапные файлы Dockerfile для разделения ресурсов во время сборки от образа контейнера среды выполнения. Использование этого типа файла помогает сохранить рабочие образы небольшими и безопасными.

  • Запуск от имени пользователя, не являемого пользователем. Запустите контейнеры .NET в качестве пользователя, не являющегося пользователем (с помощью имени пользователя или UID $APP_UID), чтобы соответствовать принципу наименьших привилегий. Это ограничивает потенциальные последствия скомпрометированного контейнера.

  • Прослушивание порта 8080. При запуске контейнеров от имени пользователя, отличного от работы, настройте приложение для прослушивания порта 8080. Это общее соглашение для пользователей, не являющихся пользователями.

  • Инкапсулировать зависимости. Убедитесь, что все зависимости для приложения инкапсулируются в образе контейнера Docker. Инкапсуляция позволяет надежно развертывать приложение на широкий спектр узлов.

  • Выберите правильные базовые изображения. Выбранный базовый образ зависит от среды развертывания. Если вы развертываете в контейнерных приложениях, например, необходимо использовать образы Docker для Linux.

Например, эталонная реализация использует многоэтапный процесс сборки. Начальные этапы компиляции и сборки приложения с помощью полного образа пакета SDK (mcr.microsoft.com/dotnet/sdk:8.0-jammy). Окончательный образ среды выполнения создается из chiseled базового образа, который исключает пакет SDK и артефакты сборки. Служба выполняется как пользователь, отличный от сети (USER $APP_UID) и предоставляет порт 8080. Зависимости, необходимые для работы приложения, включены в образ Docker, как показано командами для копирования файлов проекта и восстановления пакетов. Использование образов на основе Linux обеспечиваетmcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled совместимость с приложениями-контейнерами, для которых требуется контейнеры Linux для развертывания.

# Build in a separate stage to avoid copying the SDK into the final image.
FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src

# Restore packages.
COPY ["Relecloud.TicketRenderer/Relecloud.TicketRenderer.csproj", "Relecloud.TicketRenderer/"]
COPY ["Relecloud.Messaging/Relecloud.Messaging.csproj", "Relecloud.Messaging/"]
COPY ["Relecloud.Models/Relecloud.Models.csproj", "Relecloud.Models/"]
RUN dotnet restore "./Relecloud.TicketRenderer/Relecloud.TicketRenderer.csproj"

# Build and publish.
COPY . .
WORKDIR "/src/Relecloud.TicketRenderer"
RUN dotnet publish "./Relecloud.TicketRenderer.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

# Chiseled images contain only the minimal set of packages needed for .NET 8.0.
FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled AS final
WORKDIR /app
EXPOSE 8080

# Copy the published app from the build stage.
COPY --from=build /app/publish .

# Run as nonroot user.
USER $APP_UID
ENTRYPOINT ["dotnet", "./Relecloud.TicketRenderer.dll"]

Развертывание эталонной реализации

Разверните эталонную реализацию шаблона современного веб-приложения для .NET. В репозитории приведены инструкции по разработке и рабочему развертыванию. После развертывания реализации можно имитировать и наблюдать за шаблонами проектирования.

На следующей схеме показана архитектура эталонной реализации:

Схема, показывающая архитектуру эталонной реализации.

Скачайте файл Visio для этой архитектуры.