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

Я давно хотел реализовать мобильное приложение с использованием полной бессерверной архитектуры и, наконец, начал изучать детали. До сих пор я обнаружил, что AWS предлагает большинство сервисов, которые потребуются для такой настройки (API Gateway, Cognito, Lambda, DynamoDB, SQS и т. д.), но мне еще предстоит решить один (возможно, теоретический) проблема; источник событий.

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

Моя проблема с этим заключается в том, что у меня нет возможности хранить такое состояние в памяти, поскольку мои лямбда-функции завершаются после того, как их единственная цель была выполнена. К чему сводится мой вопрос, существует ли в настоящее время фреймворк, поддерживающий источник событий (на Java), который сохраняет текущее состояние в чем-то вроде ElastiCache (Redis). Поскольку у меня большой опыт работы с Akka, может ли Persistence сделать это? Стоит ли искать источник событий в сочетании с бессерверным бэкендом (на данный момент) или просто еще не время?

Мне пока не удалось найти много информации в документации Akka Persistence об этой (возможно, не) проблеме. Пожалуйста, дайте мне предложения относительно того, что я мог упустить в своей миссии в бессерверную вселенную; Я все еще учусь, как и все мы.


person Martijn    schedule 14.06.2017    source источник
comment
Чего я не смог выразить, так это своего беспокойства по поводу быстрого запуска Lambda и того, что Akka Persistence не может просто создать состояние перед выполнением поставленной задачи. Я предполагаю, что это начинает больше походить на журнал аудита, а не на источник событий, но я не вижу такого масштабирования достаточно хорошо.   -  person Martijn    schedule 14.06.2017


Ответы (4)


Это будет в первую очередь основано на мнении, поэтому не подходит для Stack Overflow, но я постараюсь придерживаться как можно более фактов.

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

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

person Michal Borowiecki    schedule 15.06.2017

Да, вы можете использовать источники событий в Serverless.

Один из подходов к использованию AWS — использовать DynamoDB в качестве хранилища событий. Затем вы можете использовать потоки DynamoDB с триггерами Lambda, чтобы материализовать их в хранилище состояний (которым может быть любая другая БД).

person Noel Llevares    schedule 21.08.2017

Вы можете сделать это с DynamoDB Streams, но одного Event Store недостаточно. Код, генерирующий следующее событие, должен быть сериализован, т. е. только один экземпляр кода в данный момент времени может создавать событие для конкретного агрегатного экземпляра. В противном случае порядок событий может быть не определен.

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

Решение состоит в том, чтобы иметь «Хранилище команд», представляющее собой таблицу DynamoDB, в которой хранится последняя команда для каждого агрегатного экземпляра. Таким образом, связанный поток состоит из обновлений этого элемента. Триггер Lambda для этого потока восстанавливает состояние агрегатного экземпляра с помощью хранилища событий и создает новое событие. Затем событие сохраняется в хранилище событий. Поток магазина событий заботится о публикации события.

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

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

person Werner Donné    schedule 15.08.2018

Вы можете выполнять поиск событий с помощью akka-persistence в Lambda, если вас устраивает (некоторое настраиваемое) согласованность событий и вы хотите также применить CQRS< /эм>.

Как выглядит такая установка?

У вас будет (1 или более) лямбда-функций, которые создают n экземпляров лямбда-выражений (давайте назовем их QUERY-Lambda; где n в основном не ограничено или ограничено ограничением параллелизма, доступным в вашей учетной записи), которые могут обрабатывать ваши стороны чтения (обрабатывать запросы, читая журнал/хранилище моментальных снимков и затем отвечая), и макс. 1 экземпляр лямбда-выражения на агрегат, который обрабатывает операции записи (убедитесь в этом, используя параметр concurrency в конфигурации лямбда-выражения) (давайте назовем их COMMAND-Lambda). Это важно, чтобы убедиться, что журнал не испортится, если в него будут писать более одного актера.

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

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

Для этого вам не нужно создавать несколько jar-файлов, вы можете просто развернуть один и тот же jar-файл как несколько лямбда-функций. Вы должны убедиться в том, что в вашем API-шлюзе запросы, изменяющие состояние, перенаправляются на WRITE-Lambda (s), а те, для которых согласованность не так важна, направляются на READ-Lambda (s).

Также убедитесь, что вы не создаете моментальные снимки при воспроизведении журнала, а только при обработке команд (поскольку READ-Lambdas также воспроизводит журнал и, таким образом, может повредить ваше состояние, если они будут создавать моментальные снимки).

Для лучшей производительности создавайте моментальный снимок после каждой команды, которая изменила состояние, или, по крайней мере, перед завершением работы актора, чтобы следующие вызовы выполняли минимальное количество операций чтения. Насколько я знаю, лямбды в Java также остаются активными в течение разумного времени, поэтому холодные перезагрузки не должны быть такой большой проблемой. Если они для вас, создайте какой-нибудь cron, который каждые ~ 5-10 минут вызывает лямбду, чтобы поддерживать ее в рабочем состоянии. В качестве альтернативы вы можете использовать https://doc.akka.io/docs/alpakka/current/awslambda.html, чтобы просто отправлять запрос самому себе каждые x минут. Вы можете использовать Source.tick(3 minutes), а затем просто вызывать функцию WRITE-Lambda, как показано в документации Alpakka.

Также убедитесь, что операции, в которых вам нужно общаться с двумя агрегатами (Saga/Coordinator), обрабатываются одной и той же WRITE-Lambda. Это может стать узким местом, но, конечно, вы все равно можете применить какой-то сегментирование через маршрутизацию в шлюзе API. Это просто больше усилий, чем если бы у вас был обычный кластер Akka.

Если что-то непонятно, пожалуйста, оставьте комментарий, и я постараюсь ответить.

person Dominik Dorn    schedule 01.05.2019