Платит ли AWS Lambda за время, потраченное на инициализацию кода? - PullRequest
0 голосов
/ 29 марта 2019

Если моей лямбда-функции, написанной на Python, для инициализации (во время холодного старта) требуется 1,8 секунды, а для выполнения - 400 мс, взимается ли плата за время выполнения 400 мс или за 2,2 секунды инициализации + время выполнения?

Из рентгена я вижу:

AWS X-Ray trace

Из журналов CloudWatch я вижу:

Duration: 404.42 ms Billed Duration: 500 ms Memory Size: 448 MB Max Memory Used: 113 MB

Что я понимаю из этого, так это то, что мне выставили счет за 500 мс времени выполнения, значит ли это, что инициализация кода (например, импорт материала) бесплатна?

Ответы [ 5 ]

2 голосов
/ 30 марта 2019

Так что я решил попробовать сам разобраться с небольшим экспериментом.Я создал функцию Lambda, используя Python 2.7 с 128 МБ ОЗУ , таймаут 15 секунд и активную трассировку.Я изменил пример кода, чтобы добавить 10-секундный режим ожидания сразу после оператора импорта:

print "starting import"
import json
from time import sleep
sleep(10)
print "calling handler"

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

Поскольку лямбда начала охлаждаться, я увидел это на рентгеновском снимке: AWS X-ray output - cold start

И я видел это в журналах CloudWatch:

22:06:47 starting import
22:06:57 calling handler
22:06:58 START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST
22:06:58 starting import
22:07:08 calling handler
22:07:08 END RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
22:07:08 REPORT RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Duration: 10022.57 ms   Billed Duration: 10100 ms Memory Size: 128 MB   Max Memory Used: 19 MB

Функция фактически выполнялась ДВАЖДЫ .После первого сна в течение 10 секунд он перезапустился, когда был вызван метод-обработчик, по сути, потребовалось 20 секунд, чтобы завершить выполнение , но выставил мне счет на 10 секунд.

Я запустил его снова, на этот раз теплый старт, и я получил это:

Рентгеновский выход (теплый старт): AWS X-ray output - warm start

Журналы CloudWatch (теплый старт):

22:23:16 START RequestId: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy Version: $LATEST
22:23:16 END RequestId: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
22:23:16 REPORT RequestId: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy Duration: 6.97 ms   Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 29 MB

Ничего подозрительного там нет.Я увеличил функциональную память до 192 МБ, сохранил ее, вернул обратно до 128 МБ и сохранил снова, чтобы снова начать охлаждать, и снова вызвал ее.Вывод рентгеновских снимков был таким же, как и раньше, но в журналах CloudWatch было кое-что интересное:

22:30:13 starting import
22:30:24 START RequestId: zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz Version: $LATEST
22:30:24 starting import
22:30:34 calling handler
22:30:34 END RequestId: zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz
22:30:34 REPORT RequestId: zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz Duration: 10010.85 ms   Billed Duration: 10100 ms Memory Size: 128 MB   Max Memory Used: 19 MB

Кажется, когда мой код находился в середине сна в течение 10 секунд, Lambda отключил его иперезапустил это .Время выполнения снова составило 20 секунд, но мне выставили счет за 10 секунд.Поэтому я подумал, что если вместо 1 оператора сна я добавлю 15 снов в секунду?

Обновленный код:

print "starting import"
import json
from time import sleep
for i in range(1, 16):
    sleep(1)
    print "completed {}th sleep".format(i)

print "calling handler"
def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

Время ожидания функции истекло!

Рентгеновский вывод: enter image description here

Журналы CloudWatch:

22:51:54 starting import
22:51:55 completed 1th sleep
22:51:56 completed 2th sleep
22:51:57 completed 3th sleep
22:51:58 completed 4th sleep
22:51:59 completed 5th sleep
22:52:00 completed 6th sleep
22:52:01 completed 7th sleep
22:52:02 completed 8th sleep
22:52:03 completed 9th sleep
22:52:04 START RequestId: 11111111-1111-1111-1111-111111111111 Version: $LATEST
22:52:04 starting import
22:52:05 completed 1th sleep
22:52:06 completed 2th sleep
22:52:07 completed 3th sleep
22:52:08 completed 4th sleep
22:52:09 completed 5th sleep
22:52:10 completed 6th sleep
22:52:11 completed 7th sleep
22:52:12 completed 8th sleep
22:52:13 completed 9th sleep
22:52:14 completed 10th sleep
22:52:15 completed 11th sleep
22:52:16 completed 12th sleep
22:52:17 completed 13th sleep
22:52:18 completed 14th sleep
22:52:19 END RequestId: 11111111-1111-1111-1111-111111111111
22:52:19 REPORT RequestId: 11111111-1111-1111-1111-111111111111 Duration: 15015.16 ms   Billed Duration: 15000 ms Memory Size: 192 MB   Max Memory Used: 19 MB
22:52:19
2019-03-29T22:52:19.621Z 11111111-1111-1111-1111-111111111111 Task timed out after 15.02 seconds
22:52:19 starting import
22:52:20 completed 1th sleep
22:52:21 completed 2th sleep
22:52:22 completed 3th sleep
22:52:23 completed 4th sleep
22:52:24 completed 5th sleep
22:52:25 completed 6th sleep
22:52:26 completed 7th sleep
22:52:27 completed 8th sleep
22:52:28 completed 9th sleep
22:52:29 completed 10th sleep

Фактически он выполнялся в течение 25,8 секунд, но затем истек тайм-аут и выставил мне счет на 15секунд.Код, который выполняется до вызова обработчика, работал около 9 секунд, затем Lambda отключила его и снова запустила функцию, но не завершила работу и, в конечном итоге, истекла по истечении 25,8 секунд.Если я увеличу время ожидания Lambda до 16 секунд, оно завершится за 25,8 секунды (как показано на рентгеновском снимке) и выставит мне счет на 15100 мс.

Так что это заставляет меня поверить, что если обработчикфункция не вызывается в течение 9-10 секунд после инициализации, лямбда перезапустит функцию .Так что, если инициализация кода занимает менее 10 секунд?

Обновленный код:

print "starting import"
import json
from time import sleep
for i in range(1, 10):
    sleep(1)
    print "completed {}th sleep".format(i)

print "calling handler"
def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

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

Рентгеновский вывод: enter image description here

Журналы CloudWatch:

23:23:43 starting import
23:23:44 completed 1th sleep
23:23:45 completed 2th sleep
23:23:46 completed 3th sleep
23:23:47 completed 4th sleep
23:23:48 completed 5th sleep
23:23:49 completed 6th sleep
23:23:50 completed 7th sleep
23:23:51 completed 8th sleep
23:23:52 completed 9th sleep
23:23:52 calling handler
23:23:52 START RequestId: 22222222-2222-2222-2222-222222222222 Version: $LATEST
23:23:52 END RequestId: 22222222-2222-2222-2222-222222222222
23:23:52 REPORT RequestId: 22222222-2222-2222-2222-222222222222 Duration: 0.73 ms   Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 44 MB

Как справедливо указал Steve HOUEL , это заставляет меня поверить, что Lambda не будет взимать плату за время, необходимое для инициализации вашего кода (например, импортматериал), пока он заканчивается примерно за 9 секунд .Однако, если это займет больше времени, Lambda перезапустит вашу функцию и при условии, что вы установили достаточно большой тайм-аут, выполнение функции эффективно занимает 10 секунд + обычное время холодного запуска, но вам все равно выставляется счет толькоВремя холодного запуска без добавленных 10 секунд.

0 голосов
/ 29 марта 2019

РЕДАКТИРОВАНИЕ: Ваш эксперимент выглядит правильным.

Я рекомендую прочитать этот отличный пост , в котором содержится информация о том, как биллинг работает в среде AWS Lambda.

0 голосов
/ 29 марта 2019

Это зависит от того, что вы подразумеваете под временем инициализации.

Если вы имеете в виду запуск контейнера, размещение и т. Д., Вы НЕ платите за него.

Если вы имеете в виду инициализацию кода (требуются модули, подключение к БД и т. Д.), То да, вы платите за это.

Я не знаю насчет Python, но если вы хотите увидеть его в действии в NodeJS, импортируйте модуль с блокирующей операцией перед экспортом его функций.

Например, у вас может быть этот someModule.js файл, содержащий следующий код:

for (let i = 0; i < 10000000000; i++) {}
module.exports = {
    test: () => {}
}

for loop является блокирующей операцией, поэтому module.exports будет вызываться только после завершения цикла.

Это означает, что если вы require('someModule) в своем обработчике, он будет зависать до тех пор, пока someModule не завершит экспорт всего.

const someModule = require('./someModule')

exports.handler = async event => {
    console.log(event)
}

Затем вы платите за время, потраченное на someModule, чтобы успешно экспортировать его функции.

0 голосов
/ 29 марта 2019

Вы будете платить только за init, если потратите на него более 10 секунд. В этом случае процесс инициализации возобновится, и вы начнете платить за него.

Но что вам следует знать, если после того, как ваша функция согрелась, вы не будете инициализировать ее снова (примерно до 45 минут бездействия). Затем вы заплатите только время выполнения.

0 голосов
/ 29 марта 2019

В Lambda вы получаете бесплатно:

  • Вы получаете 1 миллион запросов в месяц.
  • 400 000 ГБ-секунд вычислительного времени в месяц.

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

Цена зависит от объема памяти, выделяемой для вашей функции.

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

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

...