ベストプラクティス
次のベストプラクティスを使用して、 AWS Lambda と Atlas 間の接続を適切に管理します。
AWS Lambda ハンドラー関数の外部で MongoDB サーバーへのクライアントを定義します。
関数を呼び出すたびに新しい
MongoClient
オブジェクトを定義しないでください。定義すると、ドライバーは関数を呼び出すごとに新しいデータベース接続を作成します。こうなると、コストが高くなり、アプリケーションがデータベース接続制限を超えてしまう可能性があります。新しいMongoClient
を定義するときは、以下を行う必要があります。MongoClient
オブジェクトを一度だけ作成します。オブジェクトを保存し、関数の呼び出し全体で
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 詳細については、「接続オプション 」を参照してください。
多数のシャードを含むシャーディングされたクラスターに接続する 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 詳細については、「接続オプション 」を参照してください。
多数のシャードを含むシャーディングされたクラスターに接続する 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 詳細については、「接続オプション 」を参照してください。
多数のシャードを含むシャーディングされたクラスターに接続する 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 アドレスのみを許可できるようにします。
プライベートネットワークを使用しない場合は、マッピングされた Elastic IP アドレスを使用して NAT ゲートウェイ経由で Atlas クラスターに接続することを検討してください。それ以外の場合は、すべての IP アドレス (0.0.0.0/0) にサービス クラスターへのアクセスを許可する必要があります。
警告
0.0.0.0/0
を IP アクセス リストに追加すると、パブリック インターネットのどこからでもクラスターにアクセスできるようになります。どこからでもアクセスを許可する場合は、すべてのデータベース ユーザーについて必ず強力な認証情報を使用してください。
maxIdleTimeMS を
60000
に設定すると、アイドルタイムが 1 分経過した後に接続が自動的に閉じられます。maxIdleTimeMS
を調整すると、サーバーレス関数からのタイムアウト エラーの発生を減らすことができます。
統合 AWS アクセスを設定し、可能な場合はAWS IAM 認証を使用します。
Lambda で認証情報をハードコーディングする代わりに、AWS IAM ロールを使用して Atlas クラスターに接続できます。ハードコードされた認証情報は、AWS Lambda 環境にアクセスするすべてのユーザーが閲覧できるため、セキュリティ上のリスクが生じる可能性があります。AWS IAM 認証では、Atlas は想定された IAM ロールを通じて AWS Lambda にアクセスします。そのため、接続文字列に認証情報は必要ありません。
Atlas は、MongoDB バージョン 5.0 以降を実行しているクラスターのAWS IAM 認証をサポートしています。クラスターが要件を満たしている場合は、Lambda 接続にAWS IAM 認証を使用することを強くお勧めします。
Lambda 関数に割り当てられるメモリの量はデフォルトで 128MB になります。Lambda 関数に割り当てられるメモリの量は、128MB から 10,240MB の範囲で設定できます。十分なメモリを割り当ててください。メモリを増やして使用可能な仮想 CPU の量を増やすことで、MongoDB ドライバーのパフォーマンスを向上させます。詳しくは「メモリとコンピューティング能力」を参照してください。
AWS_STS_REGIONAL_ENDPOINTS および AWS_REGION 環境変数を設定する。
接続例
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; }
Amazon Web ServicesAmazon Web Services 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);
その他の認証
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() } }
Amazon Web ServicesAmazon Web Services 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 }; };
その他の認証
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")
Amazon Web ServicesAmazon Web Services 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
その他の認証
# 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
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(()) }
その他の認証
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() } }