Docs 菜单
Docs 主页
/
MongoDB Atlas
/

使用 AWS Lambda 管理连接

在此页面上

  • 最佳实践
  • 连接示例

使用以下最佳实践正确管理 AWS Lambda 和 Atlas 之间的连接:

  • AWS Lambda 处理程序函数 外部定义 MongoDB 服务器的客户端。

    请勿在每次调用函数时都定义一个新的 MongoClient 对象。如果这样做,则驱动程序每次函数调用都会创建新的数据库连接。这种方式的成本很高,并可能导致应用程序超过数据库连接限制。在定义新的 MongoClient 时,您应当:

    1. 创建一次 MongoClient 对象。

    2. 存储此对象,以便函数可以在函数调用之间重复使用 MongoClient

    连接示例会重复使用现有数据库连接来加快与数据库的通信,并将与数据库的连接数保持在与应用程序流量相当的合理水平。

  • 如果您有一个连接到具有许多分片的分片集群的 Lambda 函数,可能会遇到性能问题。例如,对于具有 10 个分片的分片集群,默认情况下,驱动程序会连接到所有 30 个 mongos 实例。您可以使用连接字符串中的 srvMaxHosts 选项来设置驱动程序连接到的主机的最大数量。要提高驱动程序性能,请设置 srvMaxHosts=3。例如:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    要了解详细信息,请参阅连接选项

  • 如果您有一个连接到具有许多分片的分片集群的 Lambda 函数,可能会遇到性能问题。例如,对于具有 10 个分片的分片集群,默认情况下,驱动程序会连接到所有 30 个 mongos 实例。您可以使用连接字符串中的 srvMaxHosts 选项来设置驱动程序连接到的主机的最大数量。要提高驱动程序性能,请设置 srvMaxHosts=3。例如:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    要了解详细信息,请参阅连接选项

  • 如果您有一个连接到具有许多分片的分片集群的 Lambda 函数,可能会遇到性能问题。例如,对于具有 10 个分片的分片集群,默认情况下,驱动程序会连接到所有 30 个 mongos 实例。您可以使用连接字符串中的 srvMaxHosts 选项来设置驱动程序连接到的主机的最大数量。要提高驱动程序性能,请设置 srvMaxHosts=3。例如:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    要了解详细信息,请参阅连接选项

  • 如果您的处理程序将 回调 作为最后一个参数,请将 AWS Lambda Context 对象上的 callbackWaitsForEmptyEventLoop 属性设置为 false

    context.callbackWaitsForEmptyEventLoop = false;

    这样 Lambda 函数便可返回其结果给调用者,而无需关闭 MongoDB 数据库连接。设置此属性不适用于异步处理程序

  • 如果您有一个连接到具有许多分片的分片集群的 Lambda 函数,可能会遇到性能问题。例如,对于具有 10 个分片的分片集群,默认情况下,驱动程序会连接到所有 30 个 mongos 实例。您可以使用连接字符串中的 srvMaxHosts 选项来设置驱动程序连接到的主机的最大数量。要提高驱动程序性能,请设置 srvMaxHosts=3。例如:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    要了解详细信息,请参阅连接选项

  • 如果您有一个连接到具有许多分片的分片集群的 Lambda 函数,可能会遇到性能问题。例如,对于具有 10 个分片的分片集群,默认情况下,驱动程序会连接到所有 30 个 mongos 实例。您可以使用连接字符串中的 srvMaxHosts 选项来设置驱动程序连接到的主机的最大数量。要提高驱动程序性能,请设置 srvMaxHosts=3。例如:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    要了解更多信息,请参阅连接到 MongoDB 的工具

  • 如果您有一个连接到具有许多分片的分片集群的 Lambda 函数,可能会遇到性能问题。例如,对于具有 10 个分片的分片集群,默认情况下,驱动程序会连接到所有 30 个 mongos 实例。您可以使用连接字符串中的 srvMaxHosts 选项来设置驱动程序连接到的主机的最大数量。要提高驱动程序性能,请设置 srvMaxHosts=3。例如:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    要了解更多信息,请参阅 URI 选项

  • 如果您有一个连接到具有许多分片的分片集群的 Lambda 函数,可能会遇到性能问题。例如,对于具有 10 个分片的分片集群,默认情况下,驱动程序会连接到所有 30 个 mongos 实例。您可以使用连接字符串中的 srvMaxHosts 选项来设置驱动程序连接到的主机的最大数量。要提高驱动程序性能,请设置 srvMaxHosts=3。例如:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    要了解详细信息,请参阅连接选项

  • 限制对 Atlas 集群的网络访问。

    在 Atlas 集群和 AWS Lambda 函数之间使用网络对等连接私有端点并通过私有网络连接到 Atlas 集群,以便仅允许使用 IP 访问列表中的私有 IP 地址。

    如果您不使用专用网络,请考虑使用具有映射弹性 IP 地址的 NAT 网关 连接到 Atlas 集群。否则,您必须允许所有 IP 地址(0.0.0.0/0)访问您的服务集群。

    警告

    0.0.0.0/0添加到您的 IP 访问列表中,这允许从公共互联网中的任何位置访问集群。在允许从任何位置进行访问时,请确保对所有数据库用户使用强式档案。

  • maxIdleTimeMS 设置为 60000 可在空闲时间达到 1 分钟后自动关闭连接。调整 maxIdleTimeMS 有助于减少无服务器函数发生超时错误的概率。

  • 设置统一 AWS 访问权限,并尽可能使用 AWS IAM 身份验证。

    您可以使用 AWS IAM roles 连接到 Atlas 集群,而不是在 Lambda 中硬编码凭证。任何访问您的 AWS Lambda 环境的人都可以查看硬编码凭证,这可能会带来安全风险。借助 AWS IAM 身份验证,Atlas 通过假定的 IAM 角色访问 AWS Lambda,因此您不需要在连接字符串中输入凭据。

    Atlas 支持对运行 MongoDB 5.0 或更高版本的集群进行 AWS IAM 身份验证。如果您的集群符合这些要求,则强烈建议将 AWS IAM 身份验证用于 Lambda 连接。

  • 分配给 Lambda 函数的内存量默认为 128 MB。您可将分配给 Lambda 函数的内存量配置为 128 MB 到 10,240 MB 之间。请务必分配足够的内存。增大内存以增加可用虚拟 CPU 的内存量并提高 MongoDB 驱动程序性能。要了解详情,请参阅内存和计算能力

  • 设置 AWS_STS_REGIONAL_ENDPOINTSAWS_REGION 环境变量。

string username = Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID");
string password = Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY");
string awsSessionToken = Environment.GetEnvironmentVariable("AWS_SESSION_TOKEN");
var awsCredentials =
new MongoCredential("MONGODB-AWS", new MongoExternalIdentity(username), new PasswordEvidence(password))
.WithMechanismProperty("AWS_SESSION_TOKEN", awsSessionToken);
var mongoUrl = MongoUrl.Create($"<MONGODB_URI>");
var mongoClientSettings = MongoClientSettings.FromUrl(mongoUrl);
mongoClientSettings.Credential = awsCredentials;
mongoClientSettings.ServerApi = new ServerApi(ServerApiVersion.V1, strict: true);
return new MongoClient(mongoClientSettings);
private static MongoClient MongoClient { get; set; }
private static MongoClient CreateMongoClient()
{
var mongoClientSettings = MongoClientSettings.FromConnectionString($"<MONGODB_URI>");
mongoClientSettings.ServerApi = new ServerApi(ServerApiVersion.V1, strict: true);
return new MongoClient(mongoClientSettings);
}
static ShareMongoClientLambdaHandler()
{
MongoClient = CreateMongoClient();
}
public string HandleRequest(ILambdaContext context)
{
var database = MongoClient.GetDatabase("db");
var collection = database.GetCollection<BsonDocument>("coll");
var result = collection.Find(FilterDefinition<BsonDocument>.Empty).First();
return result.ToString();
}
var client, err = mongo.Connect(context.TODO(), options.Client().ApplyURI(os.Getenv("MONGODB_URI")))
func HandleRequest(ctx context.Context) error {
if err != nil {
return err
}
return client.Ping(context.TODO(), nil)
}
public class ExampleAwsLambdaHandler implements RequestHandler<String, String> {
private final MongoClient client;
public ExampleAwsLambdaHandler() {
client = MongoClients.create(System.getenv("MONGODB_URI"));
}
@Override
public String handleRequest(final String input, final Context context) {
return client.getDatabase("admin").runCommand(new Document("ping", 1)).toJson();
}
}
const { MongoClient } = require('mongodb');
// Get the URI for the cluster then set AWS_ACCESS_KEY_ID as the username in the
// URI and AWS_SECRET_ACCESS_KEY as the password, then set the appropriate auth
// options. Note that MongoClient now auto-connects so no need to store the connect()
// promise anywhere and reference it.
const client = new MongoClient(process.env.MONGODB_URI, {
auth: {
username: process.env.AWS_ACCESS_KEY_ID,
password: process.env.AWS_SECRET_ACCESS_KEY
},
authSource: '$external',
authMechanism: 'MONGODB-AWS'
});
module.exports.handler = async function () {
const databases = await client.db('admin').command({ listDatabases: 1 });
return {
statusCode: 200,
databases: databases
};
};
const { MongoClient } = require('mongodb');
// MongoClient now auto-connects so no need to store the connect()
// promise anywhere and reference it.
const client = new MongoClient(process.env.MONGODB_URI);
module.exports.handler = async function () {
const databases = await client.db('admin').command({ listDatabases: 1 });
return {
statusCode: 200,
databases: databases
};
};
import os
from pymongo import MongoClient
client = MongoClient(host=os.environ["MONGODB_URI"])
def lambda_handler(event, context):
return client.db.command("ping")
# Require the driver library.
require "mongo"
# Create a Mongo::Client instance using AWS IAM authentication.
# CRITICAL: You must create the client instance outside the handler
# so that the client can be reused across function invocations.
client = Mongo::Client.new([ENV.fetch("MONGODB_HOST")],
auth_mech: :aws,
user: ENV.fetch("AWS_ACCESS_KEY_ID"),
password: ENV.fetch("AWS_SECRET_ACCESS_KEY"),
auth_mech_properties: {
aws_session_token: ENV.fetch("AWS_SESSION_TOKEN"),
},
database: ENV.fetch("MONGODB_DATABASE"))
def lambda_handler(event:, context:)
# Use the client to return the name of the configured database.
client.database.name
end
# Require the driver library.
require "mongo"
# Create a Mongo::Client instance.
# CRITICAL: You must create the client instance outside the handler
# so that the client can be reused across function invocations.
client = Mongo::Client.new(ENV.fetch("MONGODB_URI"))
def lambda_handler(event:, context:)
# Use the client to return the name of the configured database.
client.database.name
end
use lambda_runtime::{service_fn, LambdaEvent};
use mongodb::{
bson::doc,
options::{AuthMechanism, ClientOptions, Credential},
Client,
};
use serde_json::Value;
use tokio::sync::OnceCell;
// Initialize a global static MongoDB Client with AWS authentication. The following environment
// variables should also be set: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and, optionally,
// AWS_SESSION_TOKEN.
static MONGODB_CLIENT: OnceCell<Client> = OnceCell::const_new();
async fn get_mongodb_client() -> &'static Client {
MONGODB_CLIENT
.get_or_init(|| async {
let uri = std::env::var("MONGODB_URI")
.expect("MONGODB_URI must be set to the URI of the MongoDB deployment");
let mut options = ClientOptions::parse(&uri)
.await
.expect("Failed to parse options from URI");
let credential = Credential::builder()
.mechanism(AuthMechanism::MongoDbAws)
.build();
options.credential = Some(credential);
Client::with_options(options).expect("Failed to create MongoDB Client")
})
.await
}
// Runs a ping operation on the "db" database and returns the response.
async fn handler(_: LambdaEvent<Value>) -> Result<Value, lambda_runtime::Error> {
let client = get_mongodb_client().await;
let response = client
.database("db")
.run_command(doc! { "ping": 1 })
.await?;
let json = serde_json::to_value(response)?;
Ok(json)
}
#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
let service = service_fn(handler);
lambda_runtime::run(service).await?;
Ok(())
}
use lambda_runtime::{service_fn, LambdaEvent};
use mongodb::{bson::doc, Client};
use serde_json::Value;
use tokio::sync::OnceCell;
// Initialize a global static MongoDB Client.
static MONGODB_CLIENT: OnceCell<Client> = OnceCell::const_new();
async fn get_mongodb_client() -> &'static Client {
MONGODB_CLIENT
.get_or_init(|| async {
let uri = std::env::var("MONGODB_URI")
.expect("MONGODB_URI must be set to the URI of the MongoDB deployment");
Client::with_uri_str(uri)
.await
.expect("Failed to create MongoDB Client")
})
.await
}
// Runs a ping operation on the "db" database and returns the response.
async fn handler(_: LambdaEvent<Value>) -> Result<Value, lambda_runtime::Error> {
let client = get_mongodb_client().await;
let response = client
.database("db")
.run_command(doc! { "ping": 1 })
.await?;
let json = serde_json::to_value(response)?;
Ok(json)
}
#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
let service = service_fn(handler);
lambda_runtime::run(service).await?;
Ok(())
}

后退

模拟区域中断