Создание масштабируемой и отказоустойчивой архитектуры с помощью динамических микросервисов

Автор оригинала: Mihai Baboi, Adrian Iftene, Daniela Gîfu, Faculty of Computer Science, “Alexandru Ioan Cuza” University, General Berthelot, 16, 700483, Iasi, Romania, Institute of Computer Science, Romanian Academy - Iasi branch, Bulevardul Carol I, 8, 700505, Romania, C
  • Перевод
И снова здравствуйте. Как вы знаете, в марте OTUS запускает абсолютно новый курс «Архитектура и шаблоны проектирования». В преддверии старта курса перевели для вас большой материал про Создание масштабируемой и отказоустойчивой архитектуры с помощью динамических микросервисов. Приятного прочтения!




Аннотация


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

1. Введение


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

Возникла необходимость увеличить количество и качество программного обеспечения [1]. Одним из ключевых факторов в прояснении различных разногласий, связанных с инновационным проектированием, является адекватность использования различных инструментов для проектирования и разработки более совершенных программных систем [2]. Большой успех в этом процессе был недавно продемонстрирован системами на основе микросервисов [3], представляющими собой архитектурную парадигму, ориентированную на различные приложения (например, для людей с ограниченными возможностями) [3]. Под эгидой микросервисов растет интерес к архитектуре и дизайну. Атрибуты качества (например, масштабируемость, производительность и устойчивость к ошибкам) ​​или выбор моделей, таких как «contractual de service» [5] или API Gateway, больше не нарушают принцип YAGNI (“You aren’t gonna need it” — “Вам это не понадобится”), страдая от BDUF ошибок (“Big Design Up Front” — “Масштабное проектирование прежде всего”). Основной исследовательский вопрос на который намеревается дать ответ эта статья — как нам разработать систему, основанную на микросервисах, с такой же простотой, как и монолитную систему? И дальше, отталкиваясь от предыдущей темы, как можно создать среду, которая обеспечивает динамическое распределение вычислительной мощности между клиентами? Наша исследовательская гипотеза предлагает использовать архитектуру клиент-серверной системы, которая объединяет распределенные вычисления и микросервисы для решения этих задач.

Структура документа выглядит следующим образом: в разделе 2 представлен краткий обзор текущей литературы, поясняющей важность микросервисов, включая две известные службы, предлагаемые Azure, а в разделе 3 обсуждается предлагаемая архитектура. Раздел 4 обсуждает оценку этой системы, прежде чем делать выводы в последнем разделе.

2. Литературный обзор микросервисов


Благодаря облачной архитектуре развертывание систем микросервисов является более продуктивным, гибким и экономически эффективным [6]. Тем не менее, Циммерманн отмечает, что микросервисы являются деликатной темой исследуемой главным образом в научных кругах [7] и промышленности. Впервые термин «микросервисы» обсуждался на семинаре архитекторов программного обеспечения в Италии в мае 2011 года, чтобы описать то, что участники видели в качестве общего архитектурного стиля, недавно исследованного многими из них. Год спустя та же группа подтвердила, что термин «микросервисы» — наиболее соответствующее название. Фактически, микросервисы были разработаны как ответ на проблемы в монолитных приложениях или сервис-ориентированных архитектурах, которые затрудняют аспекты масштабируемости, сложности и зависимостей разрабатываемого приложения, вместе с использованием облегченных коммуникационных механизмов [8-9]. Поскольку монолит является программным приложением, модули которого не могут выполняться независимо, мы должны рассматривать решение, основанное на микросервисах, так как оно единственное, способное выполнять независимые друг от друга инструкции [10-11]. Большие монолиты со временем становятся проблематичными в обслуживании, и их трудно оценивать из-за их сложности, но основным недостатком является то, что они ограничивают масштабируемость продукта. Другая проблема связана с тем, что они не обеспечивают отказоустойчивость, и не дают возможности отдельному компоненту системы работать, когда не работает другой компонент, что возможно в микросервисно-ориентированных архитектурах.

В SOA (сервис-ориентированная архитектура) основные сервисы координируются с использованием двух методов: оркестровка (где есть центральный микросервис, который будет отправлять запросы другим сервисам и контролировать весь процесс путем отправки и получения ответов) и хореография (которая не предполагает каких-либо централизация, но каждая служба заранее знает, что она должна делать) [1]. Как и в случае с монолитными архитектурами и архитектурами SOA, наиболее сложной проблемой остается разбиение системы на сервисы [12]. Также ни в коем случае не следует пренебрегать вопросом предоставления конфиденциальной информации путем неконтролируемого распространения сервисов [13].

Наша архитектура сочетает в себе распределенные вычисления с микросервисами для создания среды, которая обеспечивает динамическое распределение вычислений между клиентами. Под распределенными вычислениями мы понимаем доступность обработки и хранения больших объемов данных в облаке, что является ключевым элементом в современной индустрии как внутри, так и за пределами IT области. Распределенные системы хранения предназначены для удовлетворения требований распределенных и вычислительно расширенных приложений с широкой применимостью, масштабируемостью и высокой производительностью. Хорошо известным решением является MapReduce [14], который оркестрирует вычисления путем сортировки распределенных серверов, параллельно управляя различными задачами, всеми коммуникациями и передачей данных между частями системы, обеспечивая избыточность и отказоустойчивость.

Azure Batch — еще одна модель программирования, используемая для эффективного запуска компьютеризированных приложений в параллельном или крупномасштабном режиме, без ручной настройки или управления инфраструктурой, с более мощными кластерами высокопроизводительных вычислений (HPC — high performance computing) [15]. Чтобы проиллюстрировать эти идеи, напомним вам SaaS (программное обеспечение как услуга) или клиентские приложения, которым необходимо широкое выполнение [16]. Фактически, различные IT-компании проявляют повышенный интерес к SaaS, будучи заинтересованными в снижении своих операционных расходов и, как следствие, в повышении гибкости своего бизнеса [17]. Еще один сервис, предлагаемая основными поставщиками облачных сервисов, — это Azure Functions, который позволяет запуск по требованию без необходимости явного предоставления или управления инфраструктурой [18].

Это также повышает заинтересованность приложений в легком запуске небольших фрагментов кода или «функций» в облаке. Растущий интерес к Интернету вещей (IoT) делает Azure Functions [19] превосходным решением для обработки данных, системной интеграции и создания простых API и микросервисов.

3. Методология


Структурно предлагаемая система может быть разделена на 3 разные области: (1) клиент — то, что будет выполнять задачи, назначенные сервером; (2) сервер — интерфейс с клиентом, мозг монолитных приложений; (3) область управления клиент-серверной связью, которая инкапсулирует все детали, связанные с передачей выполнения от сервера клиенту. Вся информация, передаваемая по сети между клиентом и сервером, шифруется с использованием алгоритма DES (Data Encryption Standard — Стандарт шифрования данных), а ключ изменяется с помощью протокола Диффи-Хеллмана [20], который, хотя и является уязвимым при определенных условиях, но все же реализуется в различных решения для интернет-безопасности.

3.1. Архитектура системы

Наша система в значительной степени основана на архитектурах динамических систем микросервисов. Архитектура берет за основу клиент-сервер, в котором сервер соответствует большему количеству клиентов. И сервер, и клиент выполняют веб-микросервисы, протокол связи — HTTP, формат данных — JSON. Эта архитектура полезна для распределения и динамического перераспределения ресурсов между клиентами. Такая архитектурная модель используется для построения больших, сложных и масштабируемых по горизонтали приложений, состоящих из небольших, независимых и отделенных процессов, взаимодействующих друг с другом с помощью API [21].

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


Рис. 1. Распределение сервисов клиентам.

Архитектура приложения была построена с использованием фреймворка ASP.NET MVC от Microsoft. В центральной части мы видим серверные микросервисы собственно на самом сервере, а слева и справа — множество клиентов, ожидающих запуска задач с сервера. Сервисный компонент оркестровки обеспечивает, с одной стороны, связь между сервером и клиентами, отправку задач на клиенты, а с другой стороны, он контролирует состояние этих запросов.

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

  1. Клиент подключается к серверу и инициирует протокол обмена ключами. Он также предоставит их серверу и порту, которым они будут соответствовать.
  2. Сервер уведомляет клиент следующей задачей на выполнение (задача представлена ​​парой (микросервис, входные данные)).
  3. Клиент получает задание, а затем уведомляет сервер о том, что передача и загрузка завершены либо успешно, либо неудачно.
  4. Как только соединение между двумя объектами установлено, сервер отправляет данные в формате JSON, зашифрованные с помощью DES, на обработку клиенту.
  5. Клиент получает данные и возвращает ответ (выходные данные, полученные из запущенного микросервиса на входных данных) также в формате JSON, зашифрованный с помощью DES.
  6. Каждую минуту клиент уведомляет сервер о том, что он доступен или не готов получать новые задачи.
  7. Сервер может в любое время инициализировать процедуру сброса клиента — в этом случае он сам перезагрузится и будет готов принимать новые задачи.

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

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

Для варианта расширенных микросервисов фазы взаимодействия клиента с клиентом будут следующими:

  1. Клиент инициализирует вызов на сервер с запросом результата для конкретной задачи. Он генерирует уникальный пароль, который будет использоваться один раз. Этот пароль шифруется всеми пакетами данных, отправленными с использованием алгоритма DES.
  2. Сервер принимает вызов, проверяет, доступен ли клиент. Если такой существует, он дает ответный вызов, если нет, он ничего не возвращает, и задача будет извлечена для выполнения инициирующим вызов клиентом. Кроме пакета с прямыми инструкциями, он получает дополнительные пакеты (зависимости и т. д.).
  3. Если сервер запрашивает клиента для расширенного микросервиса, он также получит уникальный одноразовый пароль (используемый для оптимизации шифрования), созданный исходным клиентом, который может зашифровать результат с помощью этого ключа.
  4. После получения результата сервер перенаправит его только первому клиенту.
  5. Клиент расшифровывает результат с помощью одноразового пароля и продолжает выполнение.

3.2. Приложение

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


Рис. 2. Интерфейс.

В первом эксперименте мы использовали 3 микросервиса следующим образом: (1) микросервис, который выполняет математическую операцию над двумя числами (используя LibraryMath), (2) микросервис, который сообщает нам, является ли число положительным (MasterOfNumbers) и (3) расширенный микросервис, который будет вызывать первый микросервис, когда он получит два числа, а результат будет отправлять во второй микросервис для извлечения информации об этом числе (UniverseOfSuperMath).

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

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


Рис. 3. Интерфейс.

У нас есть 6 полей: ClientToken — уникальный токен, связанный с каждым клиентом (когда вызов локальный и имеет localhost значение); Date — момент, когда был сделан запрос; IP & Port = IP-адрес клиента и порт, через который осуществляется связь; Function — имя вызываемой функции; Success — булевый флаг, отмечабщий успешность вызова. Например, мы замечаем, что при первом вызове (h: 8:38:21 клиент не подключен к серверу, процесс выполняется сервером). При втором вызове мы наблюдаем динамическое поведение системы, одна из задач которой выполняется одним из клиентов, а две другие выполняются сервером. Конкретнее, вызывается UniverserOfSuperMath (локально — клиент для этой задачи недоступен), который, в свою очередь, вызывает два других микросервиса, один локальный и один через клиента, делегированного для использования конкретной инструкции, и т. д.

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

На рисунке 3 справа вызов в 8:46 демонстрирует этот сценарий. Клиенты на портах 8390 и 8827 имеют локальную или сетевую проблему или просто закрывают соединение с сервером, и сервер не получает уведомление вовремя, чтобы удалить их из списка. Сервер попытается связаться с клиентами и запустить команды, но если они не отвечают своевременно, сервер берет на себя их задачи и возвращает запрошенный результат. Для подтверждения клиенты будут запрошены еще раз через некоторое время, и если они продолжат не отвечать, они будут удалены из списка доступных клиентов. Следующий вызов (8:47) больше не будет бесполезно запрашивать клиентов, которые больше не доступны, а задачи, которые пропущены доступными клиентами, будут выполняться сервером.

Преимущества и недостатки предлагаемого решения

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

В равной степени следует подчеркнуть ограничения: когда кривая мощности вычислений не соответствует кривой мощности клиентов. У нас также есть ограничение на возможность запуска этого приложения в любой операционной системе. Для этого мы решили преобразовать доступное решение из .NET в Java. Но у этого решения есть некоторые недостатки по отношению к первоначальному решению (Java предлагает более низкую скорость обработки данных и в меньшей степени динамическую передачу пакетов, нежели у нас в .NET). В настоящее время мы используем это решение, потому что .Net Core, предлагаемый Microsoft для работы на нескольких платформах, еще не является зрелым решением и не предлагает всех функций стандартной платформы .NET).

3.3. Клиент-серверные компоненты

3.3.1. Клиент

В этой архитектуре клиент представляет собой настольное приложение WPF (Windows Presentation Foundation), специально созданное для связи с сервером и выполнения различных задач, полученных от него. Поскольку приложение является исполняемым файлом, который не требует установки, операционная система должна работать с .Net Framework. По сути, веб-микросервис будет взаимодействовать с другим веб-микросервисом.

Сначала клиент запускает планировщик заданий в параллельном потоке, который каждую минуту будет пытаться уведомить сервер о своем присутствии. Задача может принимать два состояния: (1) либо есть задание для выполнения (инициализация пакета кода уже выполнена) — в этом случае оно только уведомляет сервер о своем присутствии; (2) или требует инициализации с сервером.

Инициализация с сервером включает, в первую очередь, произвольный выбор кода и порта, который будет запускать сервер, которые в свою очередь отправляются ему по протоколу обмена ключами Диффи-Хеллмана (IKE). Как только связь между этими двумя объектами будет установлена, сервер уведомит клиента пакетом инструкций для установки. Основная роль клиента — получать пакет инструкций с сервера, загружать его в память, обрабатывать информацию, полученную с сервера, и затем возвращать результат, полученный при выполнении этого пакета инструкций. Первый шаг, выполняемый клиентом, состоит в том, чтобы связаться с сервером для получения пакета инструкций. Этот пакет инструкций поставляется в виде ZIP-архива.

Перед извлечением этого пакета удалите предыдущий каталог с инструкциями из папки «process» (если он существует), затем извлеките новый контент в эту папку и загрузите его в память. Загрузка в память запускается один раз, независимо от того, сколько обращений получит клиент. Это возможно, потому что в сеансе остаются неизменными три свойства: assembly, methodInfo и type. Assembly хранит ссылку на загруженную DLL, свойство methodInfo содержит метод, вызванный из DLL, а type описывает тип DLL. Файл install.zip — это пакет инструкций, полученный от сервера, который содержит DLL, XML, изображения, файлы конфигурации и т. д. и весь скомпилированный код, который будет выполнен в будущем процессе.

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

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

Техническая проблема состояла в том, чтобы повторно инициализировать клиент с другим пакетом инструкций для выполнения. Поскольку загрузка памяти является статической в ​​специальном контексте (веб-сервер), это было возможно только путем перезапуска всего процесса для обработки DLL библиотек, загруженных в память. Для этого мы создали в Windows события, которые мы запускаем из веб-приложения, запущенного в десктопном приложении. Это необходимо, потому что мы имеем дело с двумя разными контекстами в двух разных потоках выполнения.

3.3.2. Сервер

Встроенный микросервис имеет интерфейс ILibraryMath, который предоставляет метод SimpleMath, а реализация интерфейса выполняется классом LibraryMath. Класс LibraryMath расширяет универсальный абстрактный класс MicroCore, который имеет два соответствующих параметра для ввода и вывода. Расширяя этот абстрактный класс, метод ProcessTask должен быть реализован там, где написан весь код, который должен быть выполнен, и функция Run вызывается в расширенном абстрактном классе, чтобы выполнить этот код в методе SimpleMath. Таким образом, можно определить интерфейсы и методы, не ограничиваясь каким-либо конкретным именем, но, передав код через абстрактный класс, мы получим полный контроль над кодом, который мы можем распространять среди разных клиентов. Внутри этого класса у нас без особых затруднений может быть больше функций и импортированных библиотек, если они сгруппированы в одном пакете.

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

Service1 реализует IService1 и расширяет абстрактный класс MicroCore, а затем регистрируется в MicroContainer.RegisterMicro в этом контейнере. Стоит упомянуть о существовании API, доступных в localohst/DynamicMicros/{Service}, через которые клиенты обмениваются данными с сервером. Важные действия, доступные через эти API: клиент подключается, клиент уведомляет сервер о своей активности, микросервисы расширяется и т.д. Далее мы представим классы MicroCore и MicroContainer, которые вместе образуют основу нашего приложения.

Класс MicroCore является абстрактным, универсальным классом и отвечает за вызов кода из виртуального метода ProcessTask. Это делается путем вызова метода Run, который, в свою очередь, вызывает открытый метод TaskManager. Отметим, что микросервис в свою очередь вызовет и этот метод. Когда ZIP-пакет отправляется клиенту для загрузки в память и выполнения, он отправляется со всеми его зависимостями, включая этот класс, с помощью которого выполняется управление микросервисом клиента. Управление выполнением включает десериализацию/сериализацию пакета данных для отправки, вызов самого кода, вызов других API и т. д.

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

  1. Если это вызов ExtendedService, сервер будет вызван для ответа.
  2. Если для запроса доступен клиент, он будет отправлен ему для обработки результата; в отрицательном случае сервер сам будет обрабатывать данные.
  3. Мы запрашиваем клиента для обработки данных.
  4. Если у клиента возникли проблемы, мы еще раз запрашиваем подтверждение доступности, но отправляем ответ сервера (чтобы избежать простоев и большого времени ожидания).
  5. Мы регистрируем текущую активность.

Класс MicroContainer — это пространство управления всей встроенной микросистемой. Здесь клиенты, которые подключают приложение (сервер), подключаются, и здесь происходят вызовы функций, которые расширяют абстрактный класс MicroCore для «расширенных сервисов». Это статический класс, в котором список задач, выполняемых на микросервисах, список подключенных клиентов и список задач клиента, которые выполняют эти задачи, хранятся в словаре.

При запуске класс будет зарегистрирован для интеграции в микросервис с помощью RegisterMicro. Это произойдет только один раз при инициализации. Метод AddNewClient предоставляет нам регистрацию нового клиента, обмен ключами, регистрацию IP-адреса сервера и порта, на котором он будет работать. Токен, полученный новым клиентом, будет проверен перед вставкой в ​​список клиентов для подтверждения его уникальности. Как только соединение с клиентом установлено, сервер вызовет метод InstallService, который упаковывает данные, отправляет их, и после ответа клиента он будет добавлен в словарь для этой задачи. Время обслуживания, которое будет выделено каждому клиенту, зависит от используемой стратегии. При запуске абстрактного микросервиса MicroCore, вызываемого как на сервере, так и на клиенте (с ExtendedService), выполняется запрос доступных клиентов для запрошенной задачи с помощью функции GetNextClient. Эта операция будет выполняться очень часто, и ее сложность будет напрямую влиять на время отклика приложения. Вот почему наш подход заключался в случайном выборе клиента. Это делается быстро и из наших экспериментов обеспечивает равномерное распределение вызовов.

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

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

3.4. Динамическое поведение системы микросервисов

Прежде всего, все компьютеры, на которых будут работать клиенты, могут находиться в одной или в разных сетях. В приоритете два элемента: (а) время, затраченное на передачу данных; и (b) накладные расходы, добавленные системой для управления данными (например, поиск клиента, шифрование, дешифрование, обработка ошибок и т. д.). В основном нас интересовало поведение нашей системы в локальной (LAN) и глобальной (WAN) сетях (рис. 4).


Рис. 4. Запись системы, работающей в локальной сети (первый столбец логов) и глобальной (второй столбец логов).

Столбец Task name содержит все регистрации, сделанные клиентским вызовом для каждой задачи, и столбцы Logs — часы и длительность в мс для каждой обработки задачи (слева в локальной сети и справа в глобальной сети). Отметим, что задачи имеют наибольшее время отклика на первый вызов, после чего оно уменьшается. Естественно, потому что все загрузки памяти, сохранение адресов и т. д. обычно производятся при первом вызове. Первые три задачи — это простые математические операции, которые обычно выполняются в пределах миллисекунды — время, которое также требуется для нашей системы.

Для локальной сети у нас есть в среднем 20-30 миллисекунд на задание, что происходит из шифрования, ведения логов и передачи по сети (даже если она локальная). Эта модель связи по LAN также используется в облаке, где компьютеры расположены в одном и том же месте (дата-центре), а связь между ними осуществляется по оптоволокну, задержка в сети имеет минимальные значения. Результаты показаны на рис. 4 в левой колонке логов.

Чтобы протестировать наше WAN-приложение, мы настроили маршрутизатор так, чтобы он направлял вызов с порта 80 на: http://192.168.1.160/ (сетевой адрес), а IIS (Internet Information Services) запустил приложение, и оно было доступно из любой точки за пределами локальной сети. Для запуска приложения на уровне клиента требовалось право использовать порты 8000: 9000 (произвольные порты). Клиенты были расположены в произвольных точках, соединение с публичным IP было установлено с помощью API: https://api.ipify.org/. Результаты показаны на рис. 4 в колонке логов справа.

В результатах, представленных на рис. 4, значения в правом столбце журнала по сравнению со значениями в левом столбце журнала на 16-17% выше для первых трех задач (без связи с другими микросервисами) и ± 10% для микросервисов, которые загружали документы из Интернета или взаимодействовали с базой данных на определенном сервере.

4. Оценка


В этом исследовании мы следили за поведением системы как в локальной сети (подключение 5 компьютеров через беспроводную сеть), так и в глобальной сети (используя пространство имен mihaidm.ddns.net), сравнивая нашу систему с монолитной системой, эти операции выполняется на том же компьютере (см. таблицу 1).

Таблица 1. Оценка системы для сетей.
вычисления (мс) запись в бд (мс) генерация pdf (мс)
localhost 1 4.458 15.449
lan 25 4.408 16.415
wan 54 4.826 29.309


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

В качестве численного расчета выступало произведением двух чисел. Микросервис не взаимодействует с другими микросервисами, объем информации, передаваемой по сети, невелик, а сложность сведена к минимуму, чтобы строго изучить время, затрачиваемое на задачи управления сервером, клиентом и сетью. Если вычисление выполняется сервером (localhost), сначала проверяется, есть ли доступный клиент, и, поскольку клиент не подключен, сервер обрабатывает результат. В следующем случае наличие клиентов в локальной сети показывает выполнение задачи в условиях очень быстрой работы сети, а со стороны обработки — шифрование/дешифрование, нахождение ответа клиента. Для 100 выполнений среднее время, необходимое для завершения операции, составило 25 мс, что является многообещающим значением с учетом соотношения гибкость/скорость. В случае WAN время вдвое больше, чем в локальной сети (54 мс), это объясняется процессом шифрования, транспортными затратами, но для фактического выполнения требуется полмилесекунды.

Еще одна задача, которую мы исследовали, — запись в базу данных. В частности, в качестве параметра принимается слово, которое будет записано в базу данных. Нас интересует, как быстро клиент будет связываться с базой данных, расположенной за пределами локальной области (для этого исследования база данных была размещена на www.my.gearhost.com). Обратите внимание, что значения времени выполнения в LAN и localhost близки. В глобальной сети разница заметна, поскольку на обработку, управление данными и клиентами уходит не так много времени, как на диапазон клиентов, который подключается к базе данных для вставки значения.

Последней задачей, выполненной в этом исследовании, было создание файла PDF, наше внимание было сосредоточено на оценке времени передачи данных в системе. Для этого мы загружаем файл PDF с www.pdf-archive.com/2018/05/14/diploma/diploma.pdf, который загружается в память. Система запишет имя в определенную позицию и вернет результат (в виде байтовых векторов) обратно на сервер. Для локального хоста и локальной сети разница около 1000 мс представляет собой время, необходимое для шифрования и локальной передачи файлов PDF. Для WAN полученное значение выше, потому что стоимость передачи байтового вектора очень высока.

5. Выводы и будущая работа


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

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

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

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

Ссылка на источник


Это исследование было опубликовано при поддержке программы POC-A1-A1.2.3-G-2015, в рамках проекта PrivateSky (P_40_371/13/01.09.2016) и проекта README «Интерактивное и инновационное приложение для оценки читабельности текстов на румынском языке и улучшения пользовательских стилей написания», договор №. 114/15.09.2017, MySMIS 2014 код 119286.

Ссылки


[1] Dragoni, N., Giallorenzo, S., Lluch-Lafuente, A. L., Mazzara, M., Montesi, F., Mustafin, R. (2017a) «Microservices: Yesterday, Today, and Tomorrow.» Mazzara M., Meyer B. (eds.), Present and Ulterior Software Engineering. Springer.
[2] Mazzara, M., Khanda, K., Mustafin, R., Rivera, V., Safina, L. and Silitti, A. (2018) “Microservices Science and Engineering”. In: P. Ciancarini, S. Litvinov, A. Messina, A., Sillitti, G. Succi (eds.) Proceedings of 5th International Conference in Software Engineering for Defence Applications, SEDA 2016, Springer, 10-20.
[3] Dragoni, N., Lanese, I., Larsen, S. T., Mazzara, M., Mustafin, R., and Safina, L. (2017b) “Microservices: How To Make Your Application Scale”. In: Petrenko A., Voronkov A. (eds.) Perspectives of System Informatics. PSI 2017. Lecture Notes in Computer Science, 10742. Springer, Cham.
[4] Melis, A., Mirri, S., Prandi, C., Prandini, M., Salomoni, P., and Callegati, F. (2016) “A Microservice Architecture Use Case for Persons with Disabilities”. At the 2nd EAI International Conference on Smart Objects and Technologies for Social Good, DOI: 10.1007/978-3-319-61949- 1_5.
[5] Zimmermann, O. (2017) “Microservices Tenets: Agile Approach to Service Development and Deployment, Computer Science — Research and Development”, 32 (3-4): 301-310.
[6] Xia, C., Zhang, Y., Wang, L, Coleman, S., and Liu, Y. (2018) “Microservice-based cloud robotics system for intelligent space”. In: Robotics and Autonomous Systems 110, DOI: 10.1016/j.robot.2018.10.001.
[7] Bogner, J., Fritzsch, J., Wagner, S., and Zimmermann, A. (2019) “Microservices in Industry: Insights into Technologies, Characteristics, and Software Quality”. At the 2019 IEEE International Conference on Software Architecture Workshops (ICSAW) At: Hamburg, Germany.
[8] Akentev, E., Tchitchigin, A., Safina, L., and Mzzara, M. (2017) “Verified type checker for Jolie programming language”, https:// arXiv.org/pdf/1703.05186.pdf.
[9] Černý, T., Donahoo, M.J., and Trnka, M. (2018) “Contextual understanding of microservice architecture: current and future directions”. ACM SIGAPP Applied Computing Review 17 (4): 29-45, DOI: 10.1145/3183628.3183631.
[10] Larucces, X., Santamaria, I., Colomo-Palacios, R., and Ebert, C. (2018) “Microservices”. In: IEEE Software, 35/3: 96-100.
[11] Kalske, M. (2017) “Transforming monolithic architecture towards microservice architecture”. M.Sc. Thesis, Univ. of Helsinki.
[12] Lenarduzzi, V., and Taibi, D. (2016) “MVP Explained: A Systematic Mapping Study on the Definitions of Minimal Viable Product”. At the 42th Euromicro Conference on Software Engineering and Advanced Applications (SEAA), 112-119.
[13] Taibi, D., Lenarduzzi, V., Janes, A., Liukkunen, K., and Ahmad, M. O. (2017) “Comparing Requirements Decomposition within the Scrum, Scrum with Kanban, XP, and Banana Development Processes”. In: Baumeister H., Lichter H., Riebisch M. (eds.) Agile Processes in Software Engineering and Extreme Programming. Lecture Notes in Business Information Processing, 283. Springer, Cham.
[14] Gómez, A., Benelallam, A., and Tisi, M. (2015) “Decentralized Model Persistence for Distributed Computing”. At the 3rd BigMDE Workshop, L’Aquila, Italy.
[15] Kandave, K. R. (2018) “High performance computing on Azure”. Nanette Ray (ed.), AzureCAT, Microsoft Corporation.
[16] Sreenivas, V., SriHarsha, S., and Narasimham, C. (2012) “A Cloud Model to Implement SaaS”. In: Advanced Materials Research 341-342, Trans Tech Publications, Switzerland, 499-503.
[17] Badidi, E. (2013) “A Framework for Software-As-A-Service Selection and Provisioning”. In: International Journal of Computer Networks & Communications (IJCNC), 5 (3): 189-200.
[18] Lynn, T., Rosati, P., Lejeune, A., and Emeakaroha, V. (2017) “A Preliminary Review of Enterprise Serverless Cloud Computing (Functionas-a-Service) Platforms”. At the 2017 IEEE 9th International Conference on Cloud Computing Technology and Science, 162-169.
[19] Adzic, G. and Chatley, R. (2017) “Serverless Computing: Economic and Architectural Impact”. At: ESEC/FSE’17, September 4-8, 2017, Paderborn, Germany, ACM.
[20] Diffie, W. and Hellman, M. (1976) “New directions in cryptography”. In: IEEE Transactions on, Information Theory, 22 (6): 644–654.
[21] Kratzke, N. (2015) “About Microservices, Containers and their Underestimated Impact on Network Performance”. At the CLOUD Comput. 2015, 180 arxiv.org/abs/1710.04049.

Узнать подробнее о курсе
OTUS. Онлайн-образование
Цифровые навыки от ведущих экспертов

Комментарии 2

    0
    с использованием микросервисов в ущерб монолитным архитектурам, которые теряют популярность.

    Автору вопрос — вы уверены, что они теряют популярность?
      0
      Они теряют популярность только в статьях. В реальной жизни всё далеко не так.

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

    Самое читаемое