Необходимость хранения данных в памяти Кроме эксплуатационных проблем, у FaaS есть ряд архитек-турных ограничений, делающих его малопригодным для не-которых классов приложений. Первое из них — необходимость загрузки значительного количества данных в память до обра-Глава 8. Функции и событийно-ориентированная обработка 139ботки пользовательского запроса. Ряд служб (например, служ-ба индексирования документов) требуют для своей работы загрузки в оперативную память большого количества данных. Даже при относительно высокой скорости хранилища загруз-ка большого количества данных может занять существенно больше времени, чем хотелось бы. Поскольку FaaS-функция может быть динамически инициализирована в ответ на поль-зовательский запрос, необходимость загрузки большого коли-чества данных может существенно увеличить воспринимаемую пользователем задержку обработки его запроса. Как только вы создали FaaS-сервис, он может обрабатывать большое ко-личество запросов, поэтому накладные расходы на загрузку амортизируются большим количеством обработанных запро-сов. Но если у вас запросов столько, что функция постоянно активна, вероятно, вы переплачиваете за количество обраба-тываемых запросов.
Стоимость постоянного использования запросно-ориентированных вычислений Ценовая модель облачных FaaS основана на плате за количе-ство запросов. Такой подход хорош, если запросов к сервису немного — несколько штук в минуту или в час. В такой ситу-ации сервис преимущественно бездействует и с учетом платы за количество запросов вы платите только за то время, которое ваш сервис активно обрабатывает запросы. Напротив, если вы обслуживаете запросы с помощью постоянно работающего в контейнере или на виртуальной машине сервиса, то платите за процессорное время, которое тратится преимущественно на ожидание пользовательских запросов.
Однако по мере роста сервиса количество обрабатываемых за-просов вырастает до такого уровня, что процессор все время занят их обработкой.
140Часть II. Паттерны проектирования обслуживающих систем В этот момент плата за количество запросов начинает стано-виться невыгодной. Затраты на единицу процессорного време-ни облачных виртуальных машин сокращаются по мере добав-ления ядер, а также за счет резервирования ресурсов и скидок за
длительное пользование. Затраты на оплату количества запро-сов обычно повышаются с ростом количества запросов. Следовательно, по мере роста и эволюции вашего сервиса вы, вероятно, также станете по-другому использовать подход FaaS. Идеально будет масштабироваться FaaS-сервис с открытым кодом, работающий под управлением оркестратора контейнеров вроде Kubernetes. Таким образом, вы сможете сочетать преиму-щества FaaS с выгодной ценовой моделью виртуальных машин. Паттерны FaaS
Для проектирования качественных систем жизненно важно по-нимать не только преимущества и недостатки FaaS-архитектур, но и то, как внедрить подход FaaS в распределенную систему. В данном разделе описываются несколько базовых паттернов внедрения FaaS.
Паттерн Decorator. Преобразование запроса или ответа
FaaS идеально подходит в том случае, когда нужны простые функции, которые обрабатывают входные данные, а затем пере-дают их другим сервисам. Такого рода паттерн может исполь-зоваться для расширения или декорирования HTTP-запросов,
передаваемых или принимаемых другим сервисом. Данный паттерн схематически изображен на рис. 8.1. К слову, в языках программирования существует несколько ана-логий данному паттерну. В частности, в Python есть декораторы функций , которые функционально похожи на декораторы за-Глава 8. Функции и событийно-ориентированная обработка 141
Рис. 8.1. Применение паттерна Decorator при проектировании HTTP APIпросов или ответов. Поскольку декорирующие преобразования не хранят состояния и часто добавляются постфактум по мере развития сервиса, они идеально подходят для реализации в виде FaaS. Кроме того, легковесность FaaS означает, что можно экс-периментировать с разными декораторами до тех пор, пока не найдется тот, который теснее интегрируется в реализацию сервиса.
Добавление значений по умолчанию во входные параметры HTTP RESTful API-запросов выгодно демонстрирует преимущества паттерна Decorator. Во многих API-запросах есть поля, которые необходимо заполнять разумными значениями, если они не были указаны вызывающей стороной. К примеру, вы хотите, чтобы по умолчанию поле хранило значение true . Этого трудно добиться с помощью классического JSON, поскольку в нем значение пусто-го поля по умолчанию равно null , что обычно интерпретируется как false . Чтобы решить эту проблему, можно добавить логику подстановки значений по умолчанию либо перед API-сервером, либо в коде самого приложения (например, if (field == null) field = true ). Однако оба этих подхода неоптимальны, поскольку механизм подстановки значений по умолчанию концептуально 142Часть II. Паттерны проектирования обслуживающих систем независим от обработки запроса. Вместо них мы можем исполь-зовать FaaS-паттерн Decorator, преобразующий запрос на пути между пользователем и реализацией сервиса. Учитывая сказанное ранее в разделе об одноузловых паттер-нах, вам, возможно, стало интересно, почему мы не оформили сервис подстановки значений по умолчанию в виде контейнера-адаптера. Такой подход имеет смысл, но он также означает, что масштабирование сервиса подстановки значений по умолчанию и масштабирование самого API-сервиса становятся зависимы друг от друга. Подстановка значений по умолчанию — вычисли-тельно легкая операция, и для нее, скорее всего, не понадобится много экземпляров сервиса.
Читать дальше