У меня есть программа, которая выполняет несколько тысяч монте-карло-симуляций, чтобы предсказать результат; Я не могу сказать, что они на самом деле предсказать, так что я буду использовать другой пример из "бесспорного существования Санта-Клаус", так как содержание этих алгоритмов не имеет отношения к данному вопросу. Я хочу знать, как часто посещают каждый квадрат на монополистической доске (чтобы предсказать, какие лучшие свойства купить). Для этого я имитирую тысячи игр и сопоставляю результаты. Моя текущая реализация представляет собой автономное приложение С#, но я хочу перенести его в облако, чтобы я мог предоставить это как услугу - каждый пользователь может получить персонализированные результаты, отправив количество сторон, которые есть у каждой из их костей.
Текущая реализация также довольно медленная - она очень парализуема, поскольку каждая симуляция полностью независима, но у меня есть только 8 ядер, поэтому для завершения полного предсказания требуется около 20 минут, причем около 50000 отдельных симуляторов на моей локальной машине.
План состоит в том, чтобы каждый из них выполнял одно (или несколько) симуляции AWMS-лямбда-функций, а затем сортировал их - в основном, переводил их. Я посмотрел на использование AWS EMR (Elastic MapReduce), но это слишком масштабно для того, что я хочу, и разворачивание экземпляров для запуска только вычислений, по-видимому, занимает больше времени, чем все вычисления в одиночку (что не имело бы значения для мульти- часовой автономный анализ, но я хочу, чтобы низкая латентность отвечала на веб-запрос).
Идеальный, как я вижу, будет:
Lambda 0 - Сгоняет многие другие лямбда-функции, каждый из которых выполняет небольшую часть вычисления. Лямбда 1..N - Параллельно много симуляций (число не является константой). Lambda N + 1 - Составьте все результаты и верните ответ.
Здесь есть каркас lambda mapreduce:
https://github.com/awslabs/lambda-refarch-mapreduce
Но у него, кажется, есть один главный недостаток - каждый раз, когда этап карты завершается, он записывает свои результаты на S3 (я в порядке с использованием этого как временного), затем запускает новую lambda через событие. Эта активированная лямбда смотрит, все ли были записаны на хранение. Если нет, это заканчивается, если да, то это делает шаг сокращения. Это похоже на справедливое решение, но я просто немного обеспокоен: а) опасностью гонки, когда два результата приходят вместе, могут ли два редуктора вычислить результаты? И б) похоже, что он увольняет много лямбда, которые все просто решили не запускать (я знаю, что они дешевы для запуска, но удвоение числа до двух на симуляцию - расчет и, возможно, сокращение - будет, очевидно, удвоить затраты). Есть ли способ отключить результат S3 после того, как, скажем, 100 файлов записаны в папку, а не после каждого?
Я посмотрел на использование функций шага, но я не уверен, как запустить много лямбдов параллельно за один шаг и вернуть их до того, как перейдет в состояние машины. Однако функции Step будут полезны для окончательной морщины - я хочу скрыть все это за API.
Из того, что я прочитал, API могут отключить лямбда и вернуть результат этой лямбда, но я не хочу, чтобы вызываемая лямбда была тем, кто возвращал результат. Не тогда, когда вы вместо этого вызываете функцию шага из API, результаты последнего состояния возвращаются вызовом API.
Короче говоря, я хочу:
Запрос API → Вычислить результаты параллельно → Ответ API
Это бит в середине. Я не понимаю, как это сделать, хотя я могу возвращать все результаты в ответ на исходный запрос - либо сам по себе легко.
Несколько вариантов, которые я вижу:
Используйте функцию шага, которая теперь поддерживается шлюзом AWS API, и вызывается несколько lambdas в одном состоянии, ожидая, пока все они вернутся до перехода.
Используйте AWS EMR, но как-то заставляйте инициализированные экземпляры всегда жить, чтобы избежать чрезмерных затрат времени на подготовку. Это, очевидно, отрицает масштабируемость Lambda и является более дорогостоящим.
Используйте фреймворк mapreduce или что-то подобное и найдите способ ответа на входящий запрос с другой лямбда на тот, который изначально был вызван запросом API. В идеале также уменьшите количество задействованных здесь событий S3, но это не приоритет.
Немедленно ответьте на исходный запрос API с первой лямбда, затем добавьте больше данных пользователю позже, когда закончите вычисления (они должны занимать около 30 секунд с parallelism, а домен таков, что это приемлемое время ожидания ответа, даже ответ HTTP).
Я сомневаюсь, что это будет иметь какое-то значение для решения, поскольку это просто расширение среднего бита, а не фундаментальное изменение, но реальный расчет является итеративным, и это будет:
Запрос → Mapreduce → Mapreduce → ... → Response
Пока я знаю, как связать один набор лямбда-функций внутри запроса, цепочки больше должны быть более похожими (надеюсь).
Спасибо.
P.S. Я не могу их создать, и теги aws-emr
и aws-elastic-mapreduce
пока не существуют.