Node.js 如何达到AWS Lambda并发执行限制?
更新 下面的原始测试代码在很大程度上是正确的,但是在NodeJS中,各种AWS服务的设置应该与@Michael sqlbot提供的稍有不同Node.js 如何达到AWS Lambda并发执行限制?,node.js,amazon-web-services,aws-lambda,Node.js,Amazon Web Services,Aws Lambda,更新 下面的原始测试代码在很大程度上是正确的,但是在NodeJS中,各种AWS服务的设置应该与@Michael sqlbot提供的稍有不同 // 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 manag
// 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
//管理器
const AWS=require(“AWS sdk”)
常量https=require('https');
const agent=new https.agent({
maxSockets:498//workers达到此级别;manager实例预期为+1
});
常数λ=新AWS.lambda({
apiVersion:'2015-03-31',
区域:“us-east-2”,//初始并发突发限制=500
httpOptions:{//{
//宣布睡眠承诺
const sleep=(ms)=>newpromise((resolve)=>setTimeout(resolve,ms));
//一秒钟后返回
设nStart=new Date().getTime()
等待睡眠(1000)
return new Date().getTime()-nStart;//报告实际睡眠的毫秒数
};
//经理
exports.handler=异步(事件)=>{
const invokeWorker=async()=>{
试一试{
让lambda=new AWS.lambda()//否!不要这样做,请参见上面的更新
变量参数={
FunctionName:“工作函数”,
调用类型:“请求响应”,
日志类型:“无”
};
return wait lambda.invoke(params.promise())
}
捕获(错误){
console.log(错误)
}
};
试一试{
设nStart=new Date().getTime()
让apropmises=[]
//调用工人
for(vari=1;i{返回累加器+parseInt(response.Payload)};
设nTotalWorkMs=aResponses.reduce(减速机,0)
//给我看看
让nTotalET=new Date().getTime()-nStart
返回{
作业提示:aResponses.length,
spawnCompletionMs:nSpawnMs,
spawnCompletionPct:“${Math.floor(nSpawnMs/nTotalET*10000)/100}%”,
totalElapsedMs:nTotalET,
totalWorkMs:nTotalWorkMs,
平行比:数学层(nTotalET/nTotalWorkMs*1000)/1000
}
}
捕获(错误){
console.log(错误)
}
};
答复:
{
“工作搜索”:3000,
“spawnCompletionMs”:1879年,
“产卵完成百分比”:“2.91%”,
“totalElapsedMs”:64546,
“totalWorkMs”:3004205,
“平行比”:0.021
}
请求ID:
“43f31584-238e-4af9-9c5d-95ccab22ae84”
我是否达到了我没有提到的另一个限制?我的测试代码中是否存在缺陷?我在这里试图达到3000个工作人员的限制,但没有遇到节流,我猜这是由于异步调用重试行为造成的
编辑:两个Lambda上都不涉及VPC;选择输入中的设置为“无VPC”
编辑:在修复前后显示Cloudwatch
Lambda并发性它不是决定功能可伸缩性的唯一因素。如果Lambda功能在VPC内运行,则需要一个ENI(弹性网络接口),该接口允许从容器到容器的以太网通信(Lambda功能) 可能是由于请求的ENI太多(一次50个)而导致您的节流。您可以通过查看Manager lambda函数的日志并在尝试调用其中一个子容器时查找错误消息来检查这一点。如果错误如下所示,您将知道ENI是您的问题
Lambda无法在Lambda函数的VPC中创建ENI,因为已达到网络接口的限制。
存在许多潜在的怀疑,特别是由于您从Lambda调用Lambda,但您的重点是始终看到50的并发性-一个看似任意的并发性y限制(和一个可疑的整数)-提醒我JavaScript SDK中潜伏着一个反步兵:
在Node.js中,您可以设置每个源的最大连接数。如果设置了maxSockets,则低级HTTP客户端会对请求进行排队,并在请求可用时将其分配给套接字
当然,这里,“origin”是指scheme+hostname的任何唯一组合,在本例中,它是SDK连接到的us-east-2中的Lambda服务,以便调用Invoke
方法,https://lambda.us-east-2.amazonaws.com
这使您可以设置一次对给定源的并发请求数的上限。降低此值可以减少接收到的限制或超时错误数。但是,它也可以增加内存使用率,因为请求会排队等待套接字可用
当使用默认的https
时,SDK从globalAgent
中获取maxSockets
值。如果maxSockets
值未定义或为无穷大,SDK将假定maxSockets
值为50
AWS Lambda函数的配置是什么?是否在VPC中?“我猜这是由于异步调用重试行为。”您使用的是
InvocationType:“RequestResponse”
--这意味着同步,而不是异步,即使处理程序是一个异步
函数。服务不会重试。但是,如果您也将调用程序作为lambda函数运行,那么除非调用程序函数的容器有大量可用的CPU周期(通过增加内存可以获得)它可能没有足够的资源来生成、签名和提交足够多的同步请求以正确执行测试。可能在EC2中运行。哦,这就是SDK。@Michael sqlbot ROFL!要从一个LOL中恢复过来需要一点时间。所以,实际上,这非常方便,不是吗?知道us-east-2在测试中只会给你500个在最初的突发事件中,可以将其设置为495,而不用担心会影响AWS的速度!节点正在缓存maxSockets之外的内容,这可能会导致内存问题
// 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"