更新
下面的原始测试代码基本上是正确的,但是在NodeJS中,各种AWS服务的设置应该根据@Michael-sqlbot提供的SDK link有所不同
// manager
const AWS = require("aws-sdk")
const https = require('https');
const agent = new https.Agent({
maxSockets: 498 // workers hit this level; expect plus 1 for the manager instance
});
const lambda = new AWS.Lambda({
apiVersion: '2015-03-31',
region: 'us-east-2', // Initial concurrency burst limit = 500
httpOptions: { // <--- replace the default of 50 (https) by
agent: agent // <--- plugging the modified Agent into the service
}
})
// NOW begin the manager handler code
在规划一项新服务时,我正在做一些初步的压力测试。在阅读了the 1,000 concurrent execution limit per account和initial burst rate(在us-east-2中是500)之后,我希望立即实现至少500个突发并发执行。下面的CloudWatch的Lambda指标的屏幕截图显示了其他情况。* 无论我尝试什么参数组合,我都无法超过51个并发执行 *。下面是测试代码:
// worker
exports.handler = async (event) => {
// declare sleep promise
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// return after one second
let nStart = new Date().getTime()
await sleep(1000)
return new Date().getTime() - nStart; // report the exact ms the sleep actually took
};
// manager
exports.handler = async(event) => {
const invokeWorker = async() => {
try {
let lambda = new AWS.Lambda() // NO! DO NOT DO THIS, SEE UPDATE ABOVE
var params = {
FunctionName: "worker-function",
InvocationType: "RequestResponse",
LogType: "None"
};
return await lambda.invoke(params).promise()
}
catch (error) {
console.log(error)
}
};
try {
let nStart = new Date().getTime()
let aPromises = []
// invoke workers
for (var i = 1; i <= 3000; i++) {
aPromises.push(invokeWorker())
}
// record time to complete spawning
let nSpawnMs = new Date().getTime() - nStart
// wait for the workers to ALL return
let aResponses = await Promise.all(aPromises)
// sum all the actual sleep times
const reducer = (accumulator, response) => { return accumulator + parseInt(response.Payload) };
let nTotalWorkMs = aResponses.reduce(reducer, 0)
// show me
let nTotalET = new Date().getTime() - nStart
return {
jobsCount: aResponses.length,
spawnCompletionMs: nSpawnMs,
spawnCompletionPct: `${Math.floor(nSpawnMs / nTotalET * 10000) / 100}%`,
totalElapsedMs: nTotalET,
totalWorkMs: nTotalWorkMs,
parallelRatio: Math.floor(nTotalET / nTotalWorkMs * 1000) / 1000
}
}
catch (error) {
console.log(error)
}
};
Response:
{
"jobsCount": 3000,
"spawnCompletionMs": 1879,
"spawnCompletionPct": "2.91%",
"totalElapsedMs": 64546,
"totalWorkMs": 3004205,
"parallelRatio": 0.021
}
Request ID:
"43f31584-238e-4af9-9c5d-95ccab22ae84"
我是不是碰到了一个我没有提到的不同的极限?我的测试代码中是否存在缺陷?我试图达到3,000个工作者的限制,但是没有遇到任何限制,我猜这是由于异步调用重试行为。
编辑:* 两个Lambda都不涉及VPC;选择输入中的设置为“无VPC”。*
编辑:显示修复前后的Cloudwatch
2条答案
按热度按时间ubby3x7f1#
有许多潜在的嫌疑人,特别是由于你从Lambda调用Lambda的事实,但是你一直关注并发50 -一个看似任意的限制(和可疑的整数)-提醒我JavaScript SDK中潜伏着一个反足枪:
在Node.js中,您可以设置每个源的最大连接数。如果设置了maxSockets,则低级HTTP客户端将请求排队,并在套接字可用时将其分配给套接字。
当然,这里的“origin”表示scheme + hostname的任何唯一组合,在本例中,它是us-east-2中Lambda的服务endpoint,SDK连接到该服务以调用
Invoke
方法https://lambda.us-east-2.amazonaws.com
。这允许您设置一次对给定源的并发请求数的上限。降低此值可以减少收到的限制或超时错误的数量。但是,它也会增加内存使用量,因为请求要排队等待套接字可用。
...
当使用默认值
https
时,SDK从globalAgent
中获取maxSockets
值。如果maxSockets
值未定义或为Infinity,则SDK假定maxSockets
值为50。https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/node-configuring-maxsockets.html
dohp0rv52#
Lambda并发性并不是决定函数可伸缩性的唯一因素。如果您的Lambda函数在VPC中运行,则需要一个弹性网络接口(Elastic Network Interface,ENI),允许以太网流量进出容器(Lambda函数)。
这可能是由于您的节流发生了太多的弹性网卡的要求(50一次)。您可以通过查看Manager lambda函数的日志并在它尝试调用其中一个子容器时查找错误消息来检查这一点。如果错误看起来像下面的东西,你会知道弹性网卡的是你的问题。
Lambda was not able to create an ENI in the VPC of the Lambda function because the limit for Network Interfaces has been reached.