Mejores prácticas
Utilice las siguientes prácticas recomendadas para administrar adecuadamente las conexiones entre AWS Lambda y Atlas:
Define el cliente para el servidor MongoDB fuera de la función del controlador de AWS Lambda.
No definas una nueva
MongoClientobjeto cada vez que invoca su función. Esto hace que el controlador cree una nueva conexión a la base de datos con cada llamada a la función. Esto puede ser costoso y provocar que su aplicación exceda los límites de conexión a la base de datos. Al definir un nuevoMongoClient, debe:Crea el objeto
MongoClientuna vez.Se debe almacenar el objeto para que la función pueda reutilizar el
MongoCliententre invocaciones de funciones.
El ejemplo de conexión reutiliza las conexiones de base de datos existentes para acelerar la comunicación con la base de datos y mantener el número de conexiones con la base de datos en un nivel razonable con respecto al tráfico de la aplicación.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para obtener más información, consulta la guía de Especificación de opciones de conexión.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para obtener más información, consulta Opciones de conexión.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para obtener más información, consulta Opciones de conexión.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para obtener más información, consulta Opciones de conexión.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para obtener más información, consulta Opciones de conexión.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para obtener más información, consulta Opciones de conexión.
Si el driver toma una función de retorno como su último argumento, se debe establecer la propiedad
callbackWaitsForEmptyEventLoopen el objeto de contexto de AWS Lambda en false.context.callbackWaitsForEmptyEventLoop = false; Esto permite que una función Lambda devuelva su resultado a quien la llama sin requerir que se cierre la conexión a la base de datos MongoDB. Establecer esta propiedad no es aplicable para controladores asíncronos.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para obtener más información, consulta Opciones de conexión.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para aprender más, consulta Herramientas para conectarse a MongoDB.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para más información, consulta Opciones de URI.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3 Para obtener más información, consulta Opciones de conexión.
Si hay una función Lambda que se conecta a un clúster particionado con muchas particiones, es posible que se experimenten problemas de rendimiento. Por ejemplo, con un clúster de diez particiones, el driver se conecta a las treinta instancias
mongospor defecto. Se puede usar la opciónsrvMaxHostsen la cadena de conexión para establecer el número máximo de hosts a los que se conecta el driver. Para mejorar el rendimiento del driver, se debe configurarsrvMaxHosts=3. Por ejemplo:mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3
Se debe restringir el acceso a la red al clúster de Atlas.
Conéctese a su clúster Atlas a través de una red privada utilizando un Conexión de interconexión de red entre su clúster Atlas y su Función AWS Lambda o, alternativamente, un punto final privado, para que pueda permitir solo direcciones IP privadas de su lista de acceso IP.
Si no utiliza una red privada, considere conectarse a su clúster de Atlas a través de un gateway NAT con una dirección IP elástica asignada. De lo contrario, debe permitir que todas las direcciones IP (0.0.0.0/0) accedan a su clúster de servicios.
Advertencia
Agregar
0.0.0.0/0a la lista de acceso IP permite el acceso al clúster desde cualquier lugar de la internet pública. Hay que garantizar estar usando credenciales fuertes para todos los usuarios de base de datos cuando se permita el acceso desde cualquier lugar.
Nota
Si se añade el CIDR 0.0.0.0/0 a la lista de acceso de un proyecto, Atlas envía un correo electrónico de alerta a todos los usuarios a los que se les haya otorgado un rol en el proyecto de forma directa o indirecta a través de la pertenencia al equipo (si al equipo se le otorga un rol en el proyecto).
Establecer maxIdleTimeMS en
60000para cerrar automáticamente las conexiones después de 1 minuto de inactividad. AjustarmaxIdleTimeMSpuede ayudar a reducir la ocurrencia de errores de tiempo de espera en las funciones sin servidor.
Configura el acceso unificado a AWS y utiliza la autenticación AWS IAM siempre que sea posible.
Es posible realizar la conexión a los clústeres de Atlas usando roles de AWS IAM en lugar de codificar las credenciales en Lambda. Cualquiera que acceda al entorno de AWS Lambda puede ver las credenciales codificadas, lo que puede representar un riesgo de seguridad. Con la autenticación AWS IAM, Atlas accede a AWS Lambda a través de un rol de IAM asumido, por lo que no se necesitan credenciales en las cadenas de conexión.
Atlas admite la autenticación AWS IAM para clústeres que ejecutan MongoDB versión 7.0 o superior. Recomendamos encarecidamente utilizar la autenticación de AWS IAM para las conexiones Lambda si el clúster cumple con los requisitos.
La cantidad de memoria asignada a una función Lambda por defecto es de 128 MB. Puedes configurar la cantidad de memoria asignada a una función Lambda, entre 128 MB y 10,240 MB. Asegúrate de asignar suficiente memoria. Aumenta la memoria para aumentar la cantidad de CPU virtual disponible y optimizar el rendimiento del driver de MongoDB. Para aprender más, consulta Memoria y potencia de cálculo.
Configure sus AWS_STS_REGIONAL_ENDPOINTS y AWS_REGION variables de entorno.
Ejemplo de conexión
void lambda_handler () { bson_error_t error; mongoc_init(); // Parse URI char *uri_string = "your-mongodb-atlas-connection-string"; mongoc_uri_t *uri = mongoc_uri_new_with_error (uri_string, &error); if (!uri) { fprintf (stderr, "Failed to parse URI: %s\n", error.message); return; } // Create client mongoc_client_t *client = mongoc_client_new_from_uri_with_error(uri, &error); if (!client) { fprintf(stderr, "Failed to create client: %s\n", error.message); return; } // Perform client operations here // Cleanup mongoc_client_destroy(client); mongoc_uri_destroy (uri); mongoc_cleanup(); }
using namespace aws::lambda_runtime; class ExampleAwsHandler { private: mongocxx::client mongo_client; client CreateMongoClient() { mongocxx::uri uri("mongodb://<hostname>:<port>/?authMechanism=MONGODB-AWS"); mongocxx::options::server_api server_api_options(mongocxx::options::server_api::version::k_version_1); mongocxx::options::client client_options; client_options.server_api_opts(server_api_options); return client(uri, client_options); } public: ExampleAwsHandler() : mongo_client(CreateMongoClient()) { } std::string HandleRequest() { try { using bsoncxx::builder::basic::kvp; using bsoncxx::builder::basic::make_document; auto db = mongo_client["my_database"]; auto command = make_document(kvp("hello", 1)); auto result = db.run_command(command.view()); return bsoncxx::to_json(result); } catch (const mongocxx::exception &e) { std::cerr << "MongoDB Exception: " << e.what() << std::endl; return "{}"; } } }; static invocation_response my_handler(invocation_request const &) { ExampleAwsHandler handler; std::string response = handler.HandleRequest(); return invocation_response::success(response, "application/json"); } int main() { Aws::SDKOptions options; Aws::InitAPI(options); { mongocxx::instance instance{}; run_handler(my_handler); } Aws::ShutdownAPI(options); return 0; }
Autenticación deAWS IAM
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);
Autenticación alternativa
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(); }
import ( "context" "os" runtime "github.com/aws/aws-lambda-go/lambda" "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" ) var client, err = mongo.Connect(options.Client().ApplyURI(os.Getenv("MONGODB_URI"))) func HandleRequest(ctx context.Context) error { if err != nil { return err } return client.Ping(context.TODO(), nil) }
import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; import org.bson.Document; public class ExampleAwsLambdaHandler implements RequestHandler<String, String> { private final MongoClient client; public ExampleAwsLambdaHandler() { client = MongoClients.create(System.getenv("MONGODB_URI")); } public String handleRequest(final String input, final Context context) { return client.getDatabase("admin").runCommand(new Document("ping", 1)).toJson(); } }
import com.mongodb.kotlin.client.coroutine.MongoClient import com.mongodb.kotlin.client.coroutine.MongoDatabase import org.bson.Document import kotlinx.coroutines.runBlocking import com.amazonaws.services.lambda.runtime.Context import com.amazonaws.services.lambda.runtime.RequestHandler class ExampleAwsLambdaHandler : RequestHandler<String, String> { private val client: MongoClient = MongoClient.create(System.getenv("MONGODB_URI")) override fun handleRequest(input: String, context: Context): String = runBlocking { val database: MongoDatabase = client.getDatabase("admin") val command = Document("ping", 1) val result = database.runCommand(command) result.toJson() } }
import com.mongodb.kotlin.client.MongoClient import com.mongodb.kotlin.client.MongoDatabase import org.bson.Document import com.amazonaws.services.lambda.runtime.Context import com.amazonaws.services.lambda.runtime.RequestHandler class ExampleAwsLambdaHandler : RequestHandler<String, String> { private val client: MongoClient = MongoClient.create(System.getenv("MONGODB_URI")) override fun handleRequest(input: String, context: Context): String { val database: MongoDatabase = client.getDatabase("admin") val command = Document("ping", 1) val result = database.runCommand(command) return result.toJson() } }
Autenticación deAWS IAM
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 }; };
Autenticación alternativa
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")
Autenticación deAWS IAM
# 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
Autenticación alternativa
# 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
Autenticación de AWS IAM
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) } async fn main() -> Result<(), lambda_runtime::Error> { let service = service_fn(handler); lambda_runtime::run(service).await?; Ok(()) }
Autenticación alternativa
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) } async fn main() -> Result<(), lambda_runtime::Error> { let service = service_fn(handler); lambda_runtime::run(service).await?; Ok(()) }
import org.mongodb.scala.{MongoClient, Document} import scala.concurrent.Await import scala.concurrent.duration.Duration import com.amazonaws.services.lambda.runtime.Context import com.amazonaws.services.lambda.runtime.RequestHandler class ExampleAwsLambdaHandler extends RequestHandler[String, String] { private val client: MongoClient = MongoClient(System.getenv("MONGODB_URI")) override def handleRequest(input: String, context: Context): String = { val database = client.getDatabase("admin") val command = Document("ping" -> 1) val futureResult = database.runCommand(command).toFuture() val result = Await.result(futureResult, Duration(30, "second")) result.toJson() } }