AWS Lambda 是否对初始化代码所花费的时间收费?
Does AWS Lambda charge for the time spent initializing code?
如果我用 Python 编写的 Lambda 函数需要 1.8 秒来初始化(在冷启动期间)和 400 毫秒来执行,我是按 400 毫秒的执行时间还是整个 2.2 秒的初始化 +执行时间?
从 X-Ray 中,我看到:
从 CloudWatch 日志中,我看到:
Duration: 404.42 ms Billed Duration: 500 ms Memory Size: 448 MB Max Memory Used: 113 MB
据我了解,我按 500 毫秒的执行时间收费,这是否意味着代码初始化(例如导入内容)是免费的?
您在 Lambda 中免费获得的东西是:
- 您每月收到 100 万个请求。
- 每月 400,000 GB 秒的计算时间。
持续时间是从您的代码开始执行到它 returns 或以其他方式终止的时间计算的,四舍五入到最接近的 100 毫秒。
价格取决于您分配给函数的内存量。
Lambda 每次开始执行以响应事件通知或调用调用(包括来自控制台的测试调用)时都会计算一个请求。因此,您需要为所有功能的请求总数付费。
此外,在程序启动时需要完成一些操作,例如导入库、设置数据库和初始化全局变量和类。
您需要为这部分 Lambda 初始化付费。
这取决于你所说的初始化时间。
如果您指的是容器启动、分配等,您无需为此付费。
如果您指的是代码初始化(需要模块、连接到数据库等),是的,您需要为此付费。
我不知道 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
成功导出其功能所花费的时间。
如果你花费超过 10s,你只会为 init 付费。在这种情况下,您的 init 进程将重新启动,您将开始为此付费。
但是你应该知道,一旦你的函数被预热,你就不会再次初始化它(直到大约 45 分钟不活动)。然后,您只需支付执行时间。
已编辑:您的实验看起来有效。
我建议阅读 this excellent post,其中包含有关 AWS Lambda 运行时计费方式的信息。
所以我决定尝试通过一个小实验自己弄明白。我使用 Python 2.7 和 128 MB RAM、15 秒超时 并启用了主动跟踪创建了一个 Lambda 函数。我修改了示例代码以在导入语句之后添加 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!')
}
自从 Lambda 开始变冷后,我在 X 射线输出中看到了这一点:
我在 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
函数实际上运行TWICE。第一次休眠 10 秒后,它 在调用处理程序方法时重新启动,基本上需要 20 秒才能完成执行 但我却要支付 10 秒的费用。
我又 运行 了,这次是热启动,我得到了这个:
X光输出(热启动):
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 MB,保存它并将其恢复到 128 MB 并再次保存它以确保它再次冷启动并再次调用它。 X-ray 的输出与以前相同,但 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 秒的费用。所以我想如果我添加 15 个一秒睡眠而不是 1 个睡眠语句怎么办?
更新代码:
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!')
}
函数超时!
X光输出:
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 秒内完成执行(如 X-Ray 所示)并向我收取 15100 毫秒的费用。
所以这让我相信如果在初始化后大约 9-10 秒内未调用处理程序函数,Lambda 将重新启动该函数。那如果代码初始化不到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 毫秒。 我什至将 lambda 超时更改为 1 秒,它仍然成功执行!
X 射线输出:
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 秒。
如果我用 Python 编写的 Lambda 函数需要 1.8 秒来初始化(在冷启动期间)和 400 毫秒来执行,我是按 400 毫秒的执行时间还是整个 2.2 秒的初始化 +执行时间?
从 X-Ray 中,我看到:
从 CloudWatch 日志中,我看到:
Duration: 404.42 ms Billed Duration: 500 ms Memory Size: 448 MB Max Memory Used: 113 MB
据我了解,我按 500 毫秒的执行时间收费,这是否意味着代码初始化(例如导入内容)是免费的?
您在 Lambda 中免费获得的东西是:
- 您每月收到 100 万个请求。
- 每月 400,000 GB 秒的计算时间。
持续时间是从您的代码开始执行到它 returns 或以其他方式终止的时间计算的,四舍五入到最接近的 100 毫秒。
价格取决于您分配给函数的内存量。
Lambda 每次开始执行以响应事件通知或调用调用(包括来自控制台的测试调用)时都会计算一个请求。因此,您需要为所有功能的请求总数付费。
此外,在程序启动时需要完成一些操作,例如导入库、设置数据库和初始化全局变量和类。 您需要为这部分 Lambda 初始化付费。
这取决于你所说的初始化时间。
如果您指的是容器启动、分配等,您无需为此付费。
如果您指的是代码初始化(需要模块、连接到数据库等),是的,您需要为此付费。
我不知道 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
成功导出其功能所花费的时间。
如果你花费超过 10s,你只会为 init 付费。在这种情况下,您的 init 进程将重新启动,您将开始为此付费。
但是你应该知道,一旦你的函数被预热,你就不会再次初始化它(直到大约 45 分钟不活动)。然后,您只需支付执行时间。
已编辑:您的实验看起来有效。
我建议阅读 this excellent post,其中包含有关 AWS Lambda 运行时计费方式的信息。
所以我决定尝试通过一个小实验自己弄明白。我使用 Python 2.7 和 128 MB RAM、15 秒超时 并启用了主动跟踪创建了一个 Lambda 函数。我修改了示例代码以在导入语句之后添加 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!')
}
自从 Lambda 开始变冷后,我在 X 射线输出中看到了这一点:
我在 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
函数实际上运行TWICE。第一次休眠 10 秒后,它 在调用处理程序方法时重新启动,基本上需要 20 秒才能完成执行 但我却要支付 10 秒的费用。
我又 运行 了,这次是热启动,我得到了这个:
X光输出(热启动):
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 MB,保存它并将其恢复到 128 MB 并再次保存它以确保它再次冷启动并再次调用它。 X-ray 的输出与以前相同,但 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 秒的费用。所以我想如果我添加 15 个一秒睡眠而不是 1 个睡眠语句怎么办?
更新代码:
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!')
}
函数超时!
X光输出:
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 秒内完成执行(如 X-Ray 所示)并向我收取 15100 毫秒的费用。
所以这让我相信如果在初始化后大约 9-10 秒内未调用处理程序函数,Lambda 将重新启动该函数。那如果代码初始化不到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 毫秒。 我什至将 lambda 超时更改为 1 秒,它仍然成功执行!
X 射线输出:
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 秒。