AWS пошаговая функция mapState итерации по большим полезным нагрузкам - PullRequest
1 голос
/ 20 февраля 2020

У меня есть конечный автомат, состоящий из первой задачи предварительной обработки, которая генерирует массив в качестве вывода, который используется последующим состоянием карты до l oop over. Массив вывода первой задачи стал слишком большим, и конечный автомат выдает ошибку States.DataLimitExceeded: The state/task 'arn:aws:lambda:XYZ' returned a result with a size exceeding the maximum number of characters service limit.

Вот пример yaml конечного автомата:

stateMachines:
  myStateMachine:
    name: "myStateMachine"
    definition:
      StartAt: preProcess
      States:
        preProcess:
          Type: Task
          Resource:
            Fn::GetAtt: [preProcessLambda, Arn]
          Next: mapState
          ResultPath: "$.preProcessOutput"
        mapState:
          Type: Map
          ItemsPath: "$.preProcessOutput.data"
          MaxConcurrency: 100
          Iterator:
            StartAt: doMap
            States:
              doMap:
                Type: Task
                Resource:
                  Fn::GetAtt: [doMapLambda, Arn]
                End: true
          Next: ### next steps, not relevant

Возможное решение, которое я придумал, состояло бы в том, что состояние preProcess сохраняет свой вывод в S3-сегменте, а состояние mapState считывает непосредственно из него. Это возможно? На данный момент значение preProcess равно

ResultPath: "$.preProcessOutput"

, а mapState принимает массив

ItemsPath: "$.preProcessOutput.data" в качестве ввода.

Как мне нужно адаптировать yaml, который состояние карты читает непосредственно из S3?

Ответы [ 2 ]

0 голосов
/ 21 апреля 2020

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

Единственный реальный способ решить эту проблему - это использовать иерархии пошаговых функций. То есть, шаговые функции на ваших шаговых функциях. Итак, у вас есть:

parent -> [batch1, batch2, batch...N]

А затем у каждого пакета есть несколько отдельных заданий:

batch1 -> [j1,j2,j3...jBATCHSIZE]

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

Не очень хорошее решение, хотя оно работает.

0 голосов
/ 19 марта 2020

Не думаю, что сейчас можно читать напрямую с S3. Есть несколько вещей, которые вы можете попытаться сделать, чтобы обойти это ограничение. Один делает свой собственный итератор и не использует состояние карты. Другой пример:

Пусть лямбда прочитает ваш файл s3 и разделит его на части по индексу или некоторому идентификатору / ключу. Идея этого шага состоит в том, чтобы передать итератору в Map State НАМНОГО меньшую полезную нагрузку. Скажем, ваши данные имеют следующую структуру.

[ { idx: 1, ...more keys }, {idx: 2, ...more keys }, { idx: 3, ...more keys }, ... 4,997 more objects of data ]

Допустим, вы хотите, чтобы ваш итератор обрабатывал 1000 строк одновременно. Вместо этого верните следующие кортежи, представляющие индексы из вашей лямбды: [ [ 0, 999 ], [ 1000, 1999 ], [ 2000, 2999 ], [ 3000, 3999 ], [ 4000, 4999] ]

Состояние вашей карты получит эту новую структуру данных, и каждая итерация будет одним из кортежей. Итерация № 1: [0, 999], Итерация № 2: [1000, 1999] и т. Д. c

Внутри итератора вызовите лямбду, которая использует индексы кортежей для запроса в файл S3. AWS имеет язык запросов к сегментам S3, называемый Amazon S3 Select: https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-glacier-select-sql-reference-select.html

Вот еще один замечательный ресурс о том, как использовать S3 select и переводить данные в читаемое состояние с помощью узла : https://thetrevorharmon.com/blog/how-to-use-s3-select-to-query-json-in-node-js

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

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

...