Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js AWS Lambda函数,执行5000+;对AWS SQS的承诺极不可靠_Node.js_Amazon Web Services_Async Await_Aws Lambda - Fatal编程技术网

Node.js AWS Lambda函数,执行5000+;对AWS SQS的承诺极不可靠

Node.js AWS Lambda函数,执行5000+;对AWS SQS的承诺极不可靠,node.js,amazon-web-services,async-await,aws-lambda,Node.js,Amazon Web Services,Async Await,Aws Lambda,我正在编写一个节点AWS Lambda函数,它从我的数据库中查询大约5000个项目,并通过消息将它们发送到AWS SQS队列中 我的本地环境包括使用AWS SAM local运行lambda,并使用模拟AWS SQS 我的Lambda的一个骨架示例是: async run() { try { const accounts = await this.getAccountsFromDB(); const results = await this.writeAccountsInto

我正在编写一个节点AWS Lambda函数,它从我的数据库中查询大约5000个项目,并通过消息将它们发送到AWS SQS队列中

我的本地环境包括使用AWS SAM local运行lambda,并使用模拟AWS SQS

我的Lambda的一个骨架示例是:

async run() {
  try {
    const accounts = await this.getAccountsFromDB();
    const results = await this.writeAccountsIntoQueue(accounts);
    return 'I\'ve written: ' + results + ' messages into SQS';
  } catch (e) {
    console.log('Caught error running job: ');
    console.log(e);
    return e;
  }
}
my
getAccountsFromDB()
函数没有性能问题,它几乎立即运行,返回5000个帐户的数组

我的
writeAccountsIntoQueue
函数如下所示:

async writeAccountsIntoQueue(accounts) {
  // Extract the sqsClient and queueUrl from the class 
  const { sqsClient, queueUrl } = this;
  try {
    // Create array of functions to concurrenctly call later
    let promises = accounts.map(acc => async () => await sqsClient.sendMessage({
        QueueUrl: queueUrl,
        MessageBody: JSON.stringify(acc),
        DelaySeconds: 10,
      })
    );

    // Invoke the functions concurrently, using helper function `eachLimit`
    let writtenMessages = await eachLimit(promises, 3);
    return writtenMessages;
  } catch (e) {
    console.log('Error writing accounts into queue');
    console.log(e);
    return e;
  }
}
async function eachLimit (funcs, limit) {
  let rest = funcs.slice(limit);
  await Promise.all(
    funcs.slice(0, limit).map(
      async (func) => {
        await func();
        while (rest.length) {
          await rest.shift()();
        }
      }
    )
  );
}
我的助手,
eachLimit
看起来像:

async writeAccountsIntoQueue(accounts) {
  // Extract the sqsClient and queueUrl from the class 
  const { sqsClient, queueUrl } = this;
  try {
    // Create array of functions to concurrenctly call later
    let promises = accounts.map(acc => async () => await sqsClient.sendMessage({
        QueueUrl: queueUrl,
        MessageBody: JSON.stringify(acc),
        DelaySeconds: 10,
      })
    );

    // Invoke the functions concurrently, using helper function `eachLimit`
    let writtenMessages = await eachLimit(promises, 3);
    return writtenMessages;
  } catch (e) {
    console.log('Error writing accounts into queue');
    console.log(e);
    return e;
  }
}
async function eachLimit (funcs, limit) {
  let rest = funcs.slice(limit);
  await Promise.all(
    funcs.slice(0, limit).map(
      async (func) => {
        await func();
        while (rest.length) {
          await rest.shift()();
        }
      }
    )
  );
}
据我所知,它应该将并发执行限制为
limit

此外,我还包装了AWS SDK SQS客户端,以返回一个带有
sendMessage
函数的对象,该函数如下所示:

sendMessage(params) {
  const { client } = this;
  return new Promise((resolve, reject) => {
    client.sendMessage(params, (err, data) => {
      if (err) {
        console.log('Error sending message');
        console.log(err);
        return reject(err);
      }
      return resolve(data);
    });
  });
}
所以没什么特别的,只是答应回电话


我已经将lambda设置为300秒后超时,lambda总是超时,如果不超时,它会突然结束,并错过一些应该继续的最终日志记录,这让我觉得它甚至可能在某个地方出错,只是静静地。当我检查SQS队列时,我丢失了大约1000个条目。

我可以在您的代码中看到一些问题

第一:

    let promises = accounts.map(acc => async () => await sqsClient.sendMessage({
        QueueUrl: queueUrl,
        MessageBody: JSON.stringify(acc),
        DelaySeconds: 10,
      })
    );
您正在滥用
async/await
。请始终记住,
wait
将等到您的承诺得到解决后再继续下一个承诺,在这种情况下,每当您映射数组
promises
并调用每个函数项时,它将等待该函数包装的承诺后再继续,这是不好的。由于您只对收回承诺感兴趣,您可以简单地这样做:

const promises = accounts.map(acc => () => sqsClient.sendMessage({
       QueueUrl: queueUrl,
       MessageBody: JSON.stringify(acc),
       DelaySeconds: 10,
    })
);
现在,对于第二部分,您的
eachLimit
实现看起来错误且非常冗长,我已经在的帮助下对其进行了重构,以便为您处理并发限制:

const PromisePool = require('es6-promise-pool')

function eachLimit(promiseFuncs, limit) {    
    const promiseProducer = function () {
        while(promiseFuncs.length) {
            const promiseFunc = promiseFuncs.shift();
            return promiseFunc();
        }

        return null;
    }

    const pool = new PromisePool(promiseProducer, limit)
    const poolPromise = pool.start();
    return poolPromise;
}
最后,但非常重要的一点是,看看SQS FIFO每秒最多有300次发送。由于您正在处理5k个项目,您可能会将并发限制提高到5k/(300+50),大约15个。50可以是任何正数,只是稍微偏离限制。 另外,考虑使用它可以获得更高的吞吐量,达到每秒3k的发送

编辑

正如我上面所建议的,使用
sendMessageBatch
吞吐量要高得多,因此我重构了代码,映射了您支持
sendMessageBatch
的承诺:

function chunkArray(myArray, chunk_size){
    var index = 0;
    var arrayLength = myArray.length;
    var tempArray = [];

    for (index = 0; index < arrayLength; index += chunk_size) {
        myChunk = myArray.slice(index, index+chunk_size);
        tempArray.push(myChunk);
    }

    return tempArray;
}

const groupedAccounts = chunkArray(accounts, 10);

const promiseFuncs = groupedAccounts.map(accountsGroup => {
    const messages = accountsGroup.map((acc,i) => {
        return {
            Id: `pos_${i}`,
            MessageBody: JSON.stringify(acc),
            DelaySeconds: 10
        }
    });

    return () => sqsClient.sendMessageBatch({
        Entries: messages,
        QueueUrl: queueUrl
     })
});

现在的区别是,处理的每个承诺都将发送一批大小为n(在上面的示例中为10)的消息。

我相信一些引擎现在足够聪明,可以内联一些承诺链,这些承诺链只返回另一个承诺。我可能错了-需要在以后的chrome/nodejs版本上进行测试。非常感谢您的回复和见解。我已经做了您的更改,再次运行后,看起来lambda花了一些时间执行,但突然停止。在检查队列之后,看起来好像有5266个条目被输入了队列,但是应该写入5501个条目。很难说是什么原因造成的。你有什么错误吗?您设置了什么并发限制?另外,您应该尝试使用真正的SQS,并将结果与GoAWS进行比较。没有错误或输出,我甚至将
。然后(d=>{console.log('success')}
sqsClient.sendMessage(…)
以及计数器绑定,我看到它发生了5266次左右,挂起,然后退出,没有更多输出或任何错误。我将并发性设置为10,当我回到家时,我可以对正常的SQS进行测试,“您正在滥用异步/等待”应该是“您正在滥用异步/等待”。