В последние несколько лет [1] из процесса разработки ПО исключаются задачи управления серверами — приложения превращаются в совокупность рабочих процессов, распределенной логики и хранилищ данных с внешним управлением. Такой стиль разработки называют бессерверным (serverless) [2, 3], но не потому, что серверов как таковых нет, а потому, что разработчикам не нужно заботиться об их сопровождении.

Крупные провайдеры облачных сервисов создали платформы бессерверных вычислений (AWS Lambda, Microsoft Azure Functions, Google Functions и др.), позволяющие разработчику сосредоточиться исключительно на бизнес-логике и не заниматься задачами управления инфраструктурой, ее масштабированием и подготовкой. Сама программа при этом по-прежнему выполняется на внешних серверах, которые обслуживаются провайдером облака, который обеспечивает динамическое резервирование серверов. Код запускается для выполнения при наступлении определенных событий и работает в контейнерах без сохранения состояния, при этом вызовов к контейнеру до его вывода из эксплуатации может быть сделано несколько. Кроме того, в состав серверных решений входят технологии, которые можно поделить на категории программ, поставляемых в виде сервиса (Backend as a Service, BaaS), и функций в виде сервиса (Function as a Service, FaaS).

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

FaaS, со своей стороны, предоставляет среду выполнения ПО. Бессерверные приложения — это событийно-зависимые облачные системы, разработка которых состоит в объединении сторонних сервисов, клиентской логики и вызовов удаленных процедур, запускаемых в облаке. FaaS позволяет реализовать код, который будет выполняться в изолированной среде с вызовом по триггеру. При этом каждая функция FaaS обычно соответствует небольшому элементу всего приложения. Время выполнения функций чаще всего ограничено. Например, в AWS Lambda предел составляет 15 минут — платформа FaaS ждет наступления заданного события, чтобы вызвать экземпляр функции. Такими событиями могут быть запрос клиента, событие во внешней системе, поступление потока данных и т. п. Провайдер FaaS при этом отвечает за горизонтальное масштабирование, необходимое для выполнения функций, количество которых увеличивается по мере роста числа событий.

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

Бессерверные вычисления и микросервисы

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

Микросервисы появились в ходе эволюции программных архитектур [3] как инструмент уменьшения уровня сложности ИТ-систем по сравнению с монолитными и сервисными. Это небольшие автономные программы, решающие свои отдельные узкоспециальные задачи. Из них можно составить приложение как комплект независимых сервисов, соединенных экономичными коммуникационными протоколами — обычно это API, вызываемые по HTTP. Каждый сервис может разрабатывать, тестировать и развертывать отдельная команда, независимо от других, на базе собственного технологического стека. У микросервисов есть ряд преимуществ: их можно разрабатывать на различных языках программирования, они могут масштабироваться независимо от других сервисов и их можно развертывать на оборудовании, наилучшим образом отвечающем их требованиям.

Микросервисы обычно управляются с помощью API, выполняющего роль главного механизма взаимодействия с логикой приложения. Бессерверные приложения реагируют на события, а интерфейсы программирования в них применяются как механизм создания событий. Есть возможность вызвать запуск функции после наступления события, происходящего в каком-либо источнике (базе данных, шине обмена сообщениями и др.) без использования API-шлюза. Основное отличие микросервиса от бессерверной системы — более мелкая гранулярность бессерверных функций и использование событийно-зависимой парадигмы. Можно создавать событийно-зависимые микросервисы, но предпочтительными для подобных применений считаются бессерверные приложения. Существует возможность создания микросервиса на базе цепочки бессерверных функций с использованием специальных шаблонов проектирования: Saga, Gatekeeper и др.

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

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

Преимущества и недостатки бессерверных систем

У бессерверных систем есть ряд преимуществ по сравнению с традиционными.

1. Отсутствие эксплуатационных задач (NoOps). Разработчику, применяющему бессерверные функции, достаточно писать основной код — ему не нужно заботиться о масштабировании и оркестровке. Бессерверные системы, особенно использующие BaaS, уменьшают объем работы специалистов по эксплуатации, поскольку управление инфраструктурой (например, базами данных) передается на «аутсорсинг» оператору платформы. Соответственно, разработчикам не приходится иметь дело с серверами, на которых выполняются функции.

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

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

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

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

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

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

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

4. Привязка к поставщику. После развертывания бессерверной системы на чьей-либо платформе перенести ее на другую будет весьма непросто. Привязка к поставщику усиливается, если используются предлагаемые провайдером базы данных, шины обмена сообщениями, API-шлюзы и другие проприетарные технологии. Но уже появились решения, обеспечивающие взаимозаменяемость провайдеров. К примеру, существует система Serverless Application Framework, позволяющая развертывать один и тот же код на платформах разных операторов. Тем не менее простого способа переноса данных, особенно при использовании проприетарных технологий, нет.

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

Эволюция бессерверных систем

Техническая эволюция

Бессерверные технологии меняются и делают доступным все более широкому кругу разработчиков создание крупномасштабных систем (см. рисунок). Вначале концепцию бессерверных приложений тесно связывали с использованием FaaS-платформ крупных провайдеров облаков, таких как AWS Lambda и Google Cloud Functions. Но со временем выбор технологий стал более широким. Появились открытые аналоги популярных интерфейсов FaaS, такие как Kubeless и Fission, были предложены альтернативные архитектуры.

Эволюция программных архитектур

 

Затем была представлена концепция бессерверной базы данных — появилась СУБД FaunaDB. В рамках проекта Apache Pulsar реализована событийно-зависимая обработка функций в связующем ПО для обмена сообщениями: здесь появилась возможность применять бессерверные технологии в системах обработки больших данных. Были созданы открытые и коммерческие фреймворки, позволяющие развертывать функции на платформах разных операторов: Snafu, Triggermesh и др. Благодаря развитию систем контейнеризации, таких как IBM Cloud Functions OpenWhisk, Google Cloud Run Knative и AWS Fargate, стало возможно включать в бессерверные приложения компоненты с длительным периодом выполнения.

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

Архитектурная эволюция

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

Меняются ли бессерверные архитектуры по мере появления новых технологий? Для понимания их эволюции понадобятся долгосрочные исследования. На сегодня основной источник сведений о компоновке систем на базе облачных функций и вспомогательных сервисов — каталог AWS Serverless Application Repository. По его данным, среди языков программирования на AWS Lambda с большим отрывом лидируют JavaScript и Python. Среди применяемых моделей выполнения — простые функции типа запрос-ответ, итераторы для обработки серий входных данных, диспетчеры и пр. Также, судя по имеющимся данным, половина всех приложений реализуют единственную функцию, а около 15% пользуются системами, сохраняющими состояние. Таким образом бессерверное приложение избавляют от присущего FaaS недостатка, заключающегося в отсутствии возможности сохранять состояние.

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

Нерешенные проблемы

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

Еще одна проблема — выбор оптимальных архитектурных шаблонов. Сегодня разработчикам нередко приходится использовать обходные решения для преодоления ограничений бессерверных систем [1]. Например, такие «хитрости» нужны, чтобы избежать двойной тарификации, когда при синхронном вызове ожидается получение результатов выполнения другой функции. В этой связи одна из важных задач состоит в изменении образа мышления разработчиков — переориентации на событийно-зависимую парадигму. Кроме того, сохраняется неясность относительно долгосрочной эволюции — в связи с такими недостатками, как отсутствие четких шаблонов проектирования и привязка к провайдеру, из-за которой усложняется сопровождение систем и переход на другие платформы.

Литература

1. M. Roberts, J.  Chapin.  What Is Serverless? Sebastopol, CA: O’Reilly, 2017 [Online].  URL: https://www.oreilly.com/library/view/what-is-serverless/9781491984178 (дата обращения: 01.03.2021). 

2. W. Lloyd, S. Ramesh, S. Chinthalapati, L. Ly, S.  Pallickara.  Serverless computing: An investigation of factors influencing microservice performance. In Proc. Int. Conf. Cloud Eng. (IC2E),  2018. — P.  159–169. doi: 10.1109/IC2E.2018.00039.

3. J. Nupponen, D.  Taibi.  Serverless: What it is, what to do and what not to do. In Proc. Int. Conf. Softw. Archit. (ICSA 2020),  2020. — P.  49–50. doi: 10.1109/ICSA-C50368.2020.00016.

Давид Тайби (davide.taibi@tuni.fi) — доцент, Университет Тампере; Йозеф Шпилнер (spillner@zhaw.ch) — доцент, Цюрихский университет прикладных наук; Конрад Ваврух (kwaw@7bulls.com) — сооснователь, научно-исследовательский центр 7bulls.com.

Davide Taibi, Josef Spillner, Konrad Wawruch, Serverless Computing — Where Are We Now, and Where Are We Heading? IEEE Software, January/February 2021, IEEE Computer Society. All rights reserved. Reprinted with permission.