Тестирование микросервисов в чем отличие
Перейти к содержимому

Тестирование микросервисов в чем отличие

  • автор:

Тестируем микросервисную архитектуру

Для начала немного o себе: меня зовут Кирилл, я глава отдела QA в компании Slotegrator.

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

Истоки

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

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

Разумеется, монолит имел модульную структуру — содержал отдельные классы, функции, namespace, но связи между этими модулями настолько сильны, что изменение каждого из них неизбежно отражается на работе всего приложения. Поэтому любое обновление требовало участия множества команд, и самое главное, не позволяло проводить обновления быстро.

Архитектуру нашего проекта, совсем простыми словами, можно обобщить следующим образом, мы имеем:

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

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

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

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

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

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

Почему микросервисы

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

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

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

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

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

Тестирование микросервисов

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

Главным преимуществом и одновременно трудностью тестирования является то, что они располагаются на различных серверах и написаны на разных языках программирования, таких как Java и .Net. Фактически разработчики определённого микросервиса не знают, что делают остальные микросервисы, что усложняет процесс тестирования.

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

Само тестирование можно разделить на следующие виды:

  • unit тестирование;
  • контрактное тестирование;
  • интеграционное тестирование;
  • end-to-end тестирование;
  • нагрузочное тестирование;
  • UI или функциональное тестирование.

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

Unit тестирование

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

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

Unit тестами у нас покрыто 70% функционала, и так как мы применяем CI/CD, пока они не пройдены, приложение не задеплоится.

Контрактное тестирование

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

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

Например, бэкэнд-разработчик написал код, проставил аннотации и сделал swagger-документацию. Но если swagger не провалидируется фронтендом, а QA его уже протестируют ­— мы просто зря потратим время. Поэтому и создается контракт: например, у сервиса 8 эндпоинтов, и мы знаем, в каком формате он отдаёт и принимает данные.

Контрактное тестирование необходимо для того, чтобы убедится, что все действительно так и работает. По сути, это тестирование черного ящика: как происходят процессы внутри сервиса неважно, если какая-то схема работает не по пакту — это баг.

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

Так QA может писать первичные сценарии проверки бэкэнда, который еще даже не существует. Контракт помогает понять, что ожидать. Конечно, на практике не все всегда работает гладко, не по всем микросервисам удалось создать контракт до начала разработки. Фронтенд-разработчиков у нас меньше, чем бэкенд, и им приходится подтягиваться уже после разработки.

Интеграционное тестирование

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

Так как процесс тестирования был внедрен на ранних этапах разработки, каждый отдельный сервис пришлось поднимать локально, а все зависимости других модулей — мокать. В качестве языка была выбрана Java (с момента основания компании этот язык используется для написания тестов).

Что касается сборщика, то все тоже максимально просто: наша текущая архитектура изначально использует Gradle.

Если рассмотреть нашу инфраструктуру автоматизации, то это по большей части кастомный проект, в основе которого Java и Gradle, плюс куча библиотек, таких как Junit5, Feign, Rest Assured и т.д.

Feign и Rest Assured используется вместе потому, что до перехода на микросервисную архитектуру наш проект прекрасно жил на Feign. Как библиотека для покрытия API это было лучшее решение. Но после перехода на новую архитектуру по факту вся платформа была переписана на микросервисы, которые нужно покрыть верхнеуровневыми тестами в короткий срок для возможности дальнейшего проведения интеграционного тестирования. Тут мы и подключили вторую библиотеку Rest Assured, что позволило быстро покрывать огромные куски функционала (для многих данное решение будет спорным, но на тот момент большинство новых QA работало именно с Rest Assured, что и стало решающим фактором при выборе новой библиотеки).

Для развертывания окружения в docker-контейнерах локально или на используется Java-библиотека TestContainers, которая позволяет оркестрировать docker-контейнерами непосредственно из кода тестов (testcontainers.org). При развертывании окружения поднимаются сам тестируемый сервис, а также используемые сервисом базы данных, брокер сообщений и эмулятор, который и мокает все внешние сервисы.

Так как все контейнеры мы поднимаем локально и на ранних этапах разработки, то потребовалось очень много времени на то, чтобы настроить перманентное окружение. Например, у нас есть сервис Settings, которому для работы нужны Сервисы 1 и 2, и какие-то данные с Kafka и MINO. Все это берется из переменных окружения, и за счет огромного количества зависимостей тяжело контролировать процесс поднятия одного сервиса.

Тестирование формально делится на автоматизированное и ручное. Мануальные тестировщики проводят тесты руками, не поднимая среды, и пишут тест-кейсы для автоматизаторов, упрощая им задачу. У нас два мануальщика покрывают пять автоматизаторов — очень удобно.

End-to-end тестирование

По сути своей E2E тестирует бизнес-логику, так же, как и в интеграционном, но уже не изолированно, а в масштабе всей системы.

В end-to-end тестировании мы проверяем взаимодействие всех сервисов c платформой:

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

Нагрузочное тестирование

Процесс нагрузочного тестирования будем формально разделять на 4 небольших этапа:

  • тестирование производительности (Performance Testing) — исследование времени отклика ПО при выполнении операций на разных нагрузках, в том числе на стрессовых нагрузках;
  • тестирование стабильности или надежности — исследование устойчивости ПО в режиме длительного использования с целью выявления утечек памяти, перезапуска серверов и других аспектов, влияющих на нагрузку;
  • стресс-тестирование — исследование работоспособности ПО в условиях стресса, когда нагрузка превышает максимально допустимые значения, для проверки способности системы к регенерации после стрессового состояния, а также для анализа поведения системы при аварийном изменении аппаратной конфигурации;
  • объемное тестирование (Volume Testing) — исследование производительности ПО для прогнозирования долгосрочного использования системы при увеличении объемов данных, то есть анализ готовности системы к долгосрочному использованию.

Для тестов мы используем JMeter, а сами нагрузочные скрипты написаны на Groovy.

Мы используем около пяти виртуальных машин, развернутых на AWS и у нас есть 7 физических машин. Последние используем, если нужно создать большую нагрузку — 15,000 RPS и больше. Виртуальные машины, так как они, по сути, являются «откусанными» частями одной большой машины, таких цифр показать не могут — каждый реквест нужно отправлять с подписью шифрования, и это сильно нагружает процессор. Так что VM используем для фоновой или статической нагрузки в районе 2000 RPS.

Статистику собираем в Grafana — анализируем все показатели, нагрузку на CPU, GPU, сеть, диски и т.д.

Сначала сравниваем с эталонными показателями, потом экспериментируем, например, нагружаем какое-то время процессор на 30%, делаем короткий скачок до 90%—100%, и смотрим, сколько битых запросов нам нападает.

UI или функциональное тестирование

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

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

Мы используем Java, Cucumber и самописную библиотеку для описания логики сценариев (раньше использовали Akitа сценарии, но поддержка библиотеки закончилась на Java 8, нам пришлось написать свою библиотеку для работы с UI-тестами, но в основе лежат методы именно оттуда). Cucumber используем для удобства написания самих тестов.

Так как проект большой, нам необходимо запускать огромное количество скриптов одновременно, для решения этой проблемы мы используем Selenide, который развернут на одном окружении с Jenkins.

В Jenkins создается pipeline, в котором прописываем, сколько контейнеров необходимо поднять для запуска теста.

Например, нужно протестировать email-шаблоны, которых у нас В один поток это займет Поэтому создаем pipeline в Jenkins, который этот скрипт разбивает на много маленьких контейнеров, которые поднимаются в Selenide.

Можно сказать, что Selenide — это виртуальный браузер, а Selenium — виртуальный пользователь. Одновременно поднимаются 10 контейнеров, и все тесты проходят за пару минут. Все пайплайны тоже написаны на Groovy.

После этого собираем это все в отчеты в зависимости от проекта: UI в Cucumber reports, а API-тесты — в Azure.

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

Стоило ли того

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

�� Подобається Сподобалось 16

До обраного В обраному 7

В чем разница между монолитной и микросервисной архитектурами?

В чем разница между монолитной архитектурой и архитектурой микросервисов?

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

Ключевые отличия монолитной архитектуры от микросервисов

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

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

Далее мы обсудим другие различия между двумя подходами.

Процесс разработки

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

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

Развертывание

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

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

Отладка

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

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

Модификации

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

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

Масштабирование

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

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

Влияние монолитной архитектуры и архитектуры микросервисов на эксплуатацию

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

Ускорение внедрения инноваций

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

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

Снижение рисков

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

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

Сокращение времени вывода продуктов на рынок

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

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

Сокращение совокупной стоимости владения

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

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

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

Выбор между монолитной архитектурой и архитектурой микросервисов

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

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

Размер приложения

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

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

Компетентность команды

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

Инфраструктура

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

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

Как перейти от монолитной архитектуры к архитектуре микросервисов

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

Составьте план

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

Найдите партнера по облачным технологиям

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

Примените методы DevOps

Развивайте культуру DevOps в своей организации и применяйте инструменты непрерывной интеграции и непрерывного развертывания (CI/CD) для поддержки процесса миграции. Методы DevOps для работы с программным обеспечением позволяют сократить жизненный цикл разработки благодаря применению автоматизации.

Создание микросервисов

Создавайте и развертывайте микросервисы в облачной инфраструктуре. Примените соответствующие инструменты для мониторинга состояния, отслеживания трафика, контроля безопасности микросервисов и быстрого реагирования на проблемы. Если интересно, вы можете прочитать руководство по разделению монолитного приложения IC на микросервисы.

Краткое описание различий: монолитные системы и микросервисы

Категория

Монолитная архитектура

Архитектура микросервисов

Единая кодовая база с несколькими взаимозависимыми функциями.

Независимые программные компоненты с автономными функциональными возможностями, которые взаимодействуют друг с другом через API.

Требует меньше планирования на начальном этапе, но сложность понимания и поддержки постепенно растет.

Требует больше планирования и инфраструктуры на начальном этапе, но со временем управление и обслуживание упрощаются.

Все приложение развернуто как единое целое.

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

Весь путь кода можно отслеживать в одной среде.

Требуются сложные инструменты отладки, умеющие отслеживать обмен данными между несколькими микросервисами.

Небольшие изменения влекут за собой большие риски, поскольку затрагивают всю базу кода.

Можно изменять отдельные микросервисы, не затрагивая приложение в целом.

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

При необходимости можно масштабировать отдельные микросервисы, что снижает общие затраты на масштабирование.

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

Дополнительные затраты времени и средств на создание инфраструктуры и накопление опыта в команде. С другой стороны — долгосрочная экономия затрат, более простое обслуживание и адаптивность.

Как AWS поможет вам создать архитектуру микросервисов?

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

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

  • Эластичный контейнерный сервис Amazon (Amazon ECS) для создания, изоляции и выполнения защищенных микросервисов в управляемых контейнерах, что позволяет снизить сложность операций и расходы на управление.
  • AWS Lambda для запуска микросервисов без необходимости подготавливать серверы и управлять ими.
  • AWS App Mesh для мониторинга микросервисов и управления ими.
  • AWS X-Ray для мониторинга и диагностики сложных взаимодействий микросервисов.

Создайте аккаунт AWS и начните работу с микросервисами в AWS уже сегодня.

В чем разница между SOA и микросервисами?

Сервис-ориентированная архитектура (SOA) – это метод разработки программного обеспечения, который использует программные компоненты, называемые сервисами, для создания бизнес-приложений. Каждый сервис предоставляет бизнес-возможности. Они также могут общаться друг с другом на разных платформах и языках. Разработчики применяют SOA для многократного использования сервисов в различных системах или объединения нескольких независимых сервисов для выполнения сложных задач. Архитектура микросервисов – это эволюция архитектурного стиля SOA. Хотя каждый сервис SOA представляет собой полноценную бизнес-возможность, каждый микросервис представляет собой гораздо меньший программный компонент, специализирующийся только на одной задаче. Микросервисы устраняют недостатки SOA и делают программное обеспечение более совместимым с современными облачными корпоративными средами.

Какие ограничения монолитной архитектуры позволяет устранить архитектура SOA?

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

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

Монолитные архитектуры также обеспечивают централизацию ответственности и команд разработчиков, отвечающих за все приложение. Из-за размера и сложности архитектур они сталкиваются с проблемами, связанными с непрерывной доставкой и практикой DevOps.

С помощью SOA разработчики разбивают функциональные возможности программного обеспечения на уровни поставщиков и потребителей сервисов. Эти уровни взаимодействуют и обмениваются данными по корпоративной сервисной шине (ESB). Разработчики используют SOA для упрощения сложных приложений в несколько повторно используемых сервисов.

Какие ограничения архитектуры SOA позволяет устранить архитектура микросервисов?

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

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

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

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

Архитектурные различия: SOA и микросервисы

Сервисно-ориентированная архитектура (SOA) охватывает более широкую сферу деятельности предприятия. Различные бизнес-подразделения эффективно взаимодействуют на единой платформе обмена данными. Напротив, микросервисы относятся к более узкой сфере.

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

Реализация

Внедрение SOA включает интеграцию различных типов сервисов в приложение. Это решение использует корпоративную сервисную шину для подключения таких типов услуг, как:

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

Напротив, архитектура микросервисов представляет собой более детальную и независимую реализацию SOA. Микросервисы не используют ресурсы совместно, как сервисы SOA. Каждый микросервис работает независимо, предоставляя очень специфические функции.

Связь

Для доступа к удаленным сервисам архитектура SOA использует централизованную корпоративную сервисную шину (ESB) для подключения различных сервисов к нескольким протоколам обмена сообщениями. Некоторые из этих протоколов включают SOAP, расширенный протокол очереди сообщений (AMQP) и очередь сообщений Microsoft (MSMQ). Если ESB выйдет из строя, это повлияет на все сервисы SOA.

В то же время в архитектурах микросервисов используются более простые системы обмена сообщениями, такие как API-интерфейсы RESTful, служба сообщений Java (JMS) или потоковая передача событий «издатель-подписчик» (pub/sub). Эти методы не требуют, чтобы микросервисы поддерживали активное соединение при обмене данными.

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

Хранилище данных

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

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

Развертывание

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

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

Ключевые преимущества: микросервисы и SOA

Как сервисно-ориентированная архитектура (SOA), так и микросервисы позволяют командам разработчиков эффективно создавать, развертывать и контролировать современные приложения для облачных сред. Тем не менее, микросервисы обладают определенными преимуществами по сравнению с развертываниями SOA.

Возможность повторного использования

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

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

Скорость

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

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

Гибкость управления

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

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

Когда использовать SOA или микросервисы

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

SOA

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

Микросервисы

Архитектура микросервисов – лучший вариант для поддержки гибких команд разработчиков. Разработчики могут быстро и постепенно вносить изменения в код, не влияя на стабильность приложения, используя инструменты непрерывной интеграции и непрерывной доставки (CI/CD). Лучше использовать микросервисы, когда разработчики ставят перед собой следующие цели:

  • Использование различных языков программирования, библиотек или фреймворков для создания одного приложения
  • Объединение отдельных сервисов, построенных с использованием различных программных фреймворков
  • Предоставление вычислительных ресурсов и масштабирование отдельных сервисов в режиме реального времени

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

Тестирование микросервисной архитектуры

Меня зовут Кирилл, я работаю в компании Slotegrator и возглавляю отдел QA. Наша команда занимается разработкой платформ для онлайн-казино. У этого продукта очень разнообразный функционал, который включает в себя следующие пункты:

  • Модуль регистрации и авторизации;
  • Пополнение баланса и отслеживание статуса;
  • Подтверждение пользователей;
  • Бонусный модуль и т. д.

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

Как все начиналось?

В начале моей карьеры в Slotegrator, наша команда из 30-ти человек работала с 5-6 клиентами. И этого было достаточно, чтобы создавать платформу на PHP-монолите. То есть, она была построена как единое целое, где вся логическая обработка запросов помещалась внутрь одного процесса.

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

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

Архитектура нашего продукта включает в себя следующие пункты:

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

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

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

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

Почему микросервисы?

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

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

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

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

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

Тестирование микросервисов

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

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

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

  • unit-тестирование;
  • контрактное тестирование;
  • интеграционное тестирование;
  • end-to-end тестирование;
  • нагрузочное тестирование;
  • UI- или функциональное тестирование.

Теперь рассмотрим подробнее все виды тестирования.

Unit-тестирование

Unit-тестирование (модульное тестирование) — это вид тестирования ПО, позволяющий проверить корректность отдельных модулей или компонентов программного обеспечения. Цель: проверка того, что каждая единица программного кода работает корректно.

Unit-тестирование бывает двух видов:

  • позитивное (проверить поведение методов в нормальных условиях);
  • негативное (проверить устойчивость системы к нештатным ситуациям).

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

Мы покрыли 70% функционала unit-тестами, и поскольку используем CI/CD, то не можем развернуть приложение, пока они не пройдены.

Контрактное тестирование

У нас работают над микросервисами несколько команд:

  • бэкенд;
  • фронтенд;
  • тестировщики.

Чтобы понимать какой ендпоинт и в каком формате отдаёт и принимает данные, мы договариваемся между собой. Для этого, используем контракт между командами, который называется Pact. Он содержит в себе все методы и возвраты всех сервисов.

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

Наша команда работает с контрактным тестированием следующим образом: мы получаем ТЗ, которое согласованно со всеми стейкхолдерами. Согласно техническому заданию, мы оцениваем задачи и создаем схему работы.

Интеграционное тестирование

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

End-to-end тестирование

E2E тестирует бизнес-логику подобно процессу тестирования в интеграционном, но уже не изолированно, а в масштабе всей системы.

В end-to-end тестировании проверяется, как взаимодействуют все сервисы c платформой:

  • регистрация;
  • авторизация;
  • игровая деятельность;
  • пополнение и снятие денежных средств.

То есть мы проверяем насколько соответствует все приложение запросам заказчика.

Нагрузочное тестирование

Процесс нагрузочного тестирования формально делится на 4 этапа:

  • тестирование производительности (Performance Testing);
  • тестирование стабильности или надежности;
  • стресс-тестирование;
  • объемное тестирование (Volume Testing).

Для тестирования, мы используем JMeter, а сами нагрузочные скрипты написаны на Groovy.

Также, мы используем около пяти виртуальных машин, развернутых на AWS и у нас есть 7 физических машин. Физические машины, мы используем если нам необходимо создать большую нагрузку от 15,000 RPS и более. Виртуальные машины такие показатели дать не могут, поскольку каждый запрос необходимо отправлять с подписью шифрования, вследствие чего процессор сильно нагружается. Поэтому, мы используем виртуальные машины только для фоновой или статической нагрузки — 2000 RPS.

Что касается статистики, мы её собираем в Grafana. После чего, мы анализируем все показатели, такие как нагрузка на CPU, GPU, сеть, диски и т. д.

UI- или функциональное тестирование

Это итоговый вид тестирования. Мы тестируем практически все то же самое, что и при end-to-end тестировании, но только с использованием UI. Мы проводим UI тестирование мануально и также делаем автотесты.

Вывод

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *