带有猫鼬的AWS lambda到Atlas-MongoNetworkError

时间:2019-07-03 21:25:36

标签: node.js mongodb amazon-web-services mongoose aws-lambda

我试图用Mongoose和AWS Lambda连接MongoDB Atlas,但出现错误MongoNetworkError

  • AWS Lambda
  • 猫鼬
  • MongoDB地图集

同一代码已通过serverless-offline进行了测试,并且可以完美运行,问题出在我将其部署到AWS Lambda上时。

这是代码片段

'use strict';
const mongoose = require('mongoose');
const MongoClient = require('mongodb').MongoClient;
let dbuser  = process.env.DB_USER;
let dbpass = process.env.DB_PASSWORD;
let opts = { 
    bufferCommands: false, 
    bufferMaxEntries: 0, 
    socketTimeoutMS: 2000000, 
    keepAlive: true, 
    reconnectTries: 30, 
    reconnectInterval: 500,
    poolSize: 10,
    ssl: true,
 };
const uri = `mongodb+srv://${dbuser}:${dbpass}@carpoolingcluster0-bw91o.mongodb.net/awsmongotest?retryWrites=true&w=majority`;
// simple hello test
module.exports.hello = async (event, context, callback) => {
    const response = {
        body: JSON.stringify({message:'AWS Testing :: '+ `${dbuser} and ${dbpass}`}),
    };
    return response;
};
// connect using mongoose
module.exports.cn1 = async (event, context, callback)  => {
    context.callbackWaitsForEmptyEventLoop = false;
    let conn = await mongoose.createConnection(uri, opts);
    const M = conn.models.Test || conn.model('Test', new mongoose.Schema({ name: String }));
    const doc = await M.find();
    const response = {
        body: JSON.stringify({data:doc}),
    };
    return response;
};
// connect using mongodb
module.exports.cn2 = (event, context, callback) => {
    context.callbackWaitsForEmptyEventLoop = false;
    console.log("Connec to mongo using connectmongo ");
    MongoClient.connect(uri).then(client => {
        console.log("Success connect to mongo DB::::");
        client.db('awsmongotest').collection('tests').find({}).toArray()
            .then((result)=>{
                let response = {
                    body: JSON.stringify({data:result}),
                }
                callback(null, response)
            })
    }).catch(err => {
        console.log('=> an error occurred: ', err);
        callback(err);
    });
};

在CloudWatch日志中,我看到此错误

{
    "errorType": "MongoNetworkError",
    "errorMessage": "failed to connect to server [carpoolingcluster0-shard-00-02-bw91o.mongodb.net:27017] on first connect [MongoNetworkError: connection 5 to carpoolingcluster0-shard-00-02-bw91o.mongodb.net:27017 closed]",
    "stack": [
        "MongoNetworkError: failed to connect to server [carpoolingcluster0-shard-00-02-bw91o.mongodb.net:27017] on first connect [MongoNetworkError: connection 5 to carpoolingcluster0-shard-00-02-bw91o.mongodb.net:27017 closed]",
        "    at Pool.<anonymous> (/var/task/node_modules/mongodb-core/lib/topologies/server.js:431:11)",
        "    at Pool.emit (events.js:189:13)",
        "    at connect (/var/task/node_modules/mongodb-core/lib/connection/pool.js:557:14)",
        "    at callback (/var/task/node_modules/mongodb-core/lib/connection/connect.js:109:5)",
        "    at runCommand (/var/task/node_modules/mongodb-core/lib/connection/connect.js:129:7)",
        "    at Connection.errorHandler (/var/task/node_modules/mongodb-core/lib/connection/connect.js:321:5)",
        "    at Object.onceWrapper (events.js:277:13)",
        "    at Connection.emit (events.js:189:13)",
        "    at TLSSocket.<anonymous> (/var/task/node_modules/mongodb-core/lib/connection/connection.js:350:12)",
        "    at Object.onceWrapper (events.js:277:13)",
        "    at TLSSocket.emit (events.js:189:13)",
        "    at _handle.close (net.js:597:12)",
        "    at TCP.done (_tls_wrap.js:388:7)"
    ],
    "name": "MongoNetworkError",
    "errorLabels": [
        "TransientTransactionError"
    ]
}

以下是github上重现该错误的示例。

https://github.com/rollrodrig/error-aws-mongo-atlas

只需克隆它,npm安装,添加您的mongo atlas用户,密码并推送到AWS。

谢谢。

3 个答案:

答案 0 :(得分:0)

让lambda调用外部端点需要一些额外的步骤

https://aws.amazon.com/premiumsupport/knowledge-center/internet-access-lambda-function/

您的图集还应将连接Lambda的服务器的IP地址列入白名单。

要考虑的另一种选择-在您的Lambda VPC和Atlas之间使用VPC peering

答案 1 :(得分:0)

我对您的配置有一些疑问:

  1. 您是否在Atlas中将AWS Lambda函数的IP地址列入白名单? SO上的几则帖子表明,如果IP未列入白名单,则用户会收到类似MongoNetworkError的错误。 [1] [4]

  2. 您是否阅读过Atlas的最佳做法指南,其中指出mongodb连接应该在lambda处理程序之外启动? [2] [3]

  3. 您是在VPC内使用公共Lambda函数还是Lambda函数?它们之间存在实质性差异,而后者则更容易出错,因为必须考虑VPC配置(例如NAT)。

我能够ping通Atlas群集中的实例,并能够在端口27017上建立连接。但是,通过mongo shell连接时,出现以下错误:

  

无法达到设置CarpoolingCluster0-shard-0的主要级别。

     

无法到达用于设置CarpoolingCluster0-shard-0的任何节点。请检查网络连接和设备状态。连续进行了1次检查。

当我使用来自AWS lambda的GitHub示例时,会收到与问题中所述完全相同的错误消息。

由于错误消息与身份验证无关,而与网络相关,因此我认为是某种原因阻止了连接...请仔细检查上述三个配置问题。

[1] What is a TransientTransactionError in Mongoose (or MongoDB)?
[2] https://docs.atlas.mongodb.com/best-practices-connecting-to-aws-lambda/
[3] https://blog.cloudboost.io/i-wish-i-knew-how-to-use-mongodb-connection-in-aws-lambda-f91cd2694ae5
[4] https://github.com/Automattic/mongoose/issues/5237

答案 2 :(得分:0)

好,谢谢大家。最终,我在mongo支持的帮助下找到了解决方案。 这是需要的人的解决方案

  1. 创建Mongo Altas集群时,他们会要求您添加本地ip,它将自动添加到白名单中。你可以在里面看到它 Your cluster > Network Access > IP Whitelist在列表中,您将看到您的IP。这意味着只有您网络中的人才能连接到您的MongoAtlas。 AWS Lambda不在您的网络中,所以aws lambda永远不会连接到您的Mongo Atlas。这就是为什么我得到错误MongoNetworkError的原因。

修复

  1. 您需要将AWS Lambda IP添加到Mongo Atlas WhiteListIP
  2. 转到您的Your cluster > Network Access > IP Whitelist
  3. 单击按钮ADD IP ADDRESS
  4. 单击ALLOW ACCESS FROM ANYWHERE,它将IP 0.0.0.0/0添加到列表中,单击confirm
  5. 测试来自AWS Lambda的呼叫,我会工作。

最后!

您所做的就是告诉Mongo Atlas,来自任何地方的任何人都可以连接到您的mongo Atlas。

当然,这不是一个好习惯。您只需要添加AWS Lambda IP,这就是VPC出现的时间。 创建一个VPC并不复杂,并且有很多陡峭之处,其他评论中都有很好的教程。

但是可以肯定的是,这个小指南MongoNetworkError