AWS Lambda で接続を管理する
ベストプラクティス
次のベストプラクティスを使用して、 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 詳細については、「接続オプション 」を参照してください。
ハンドラーが最後の引数としてコールバックを取る場合は、 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 アドレスのみを許可できるようにします。
プライベートネットワークを使用しない場合は、マッピングされた 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 環境変数を設定する。
接続例
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(); }
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")); } public String handleRequest(final String input, final Context context) { return client.getDatabase("admin").runCommand(new Document("ping", 1)).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(()) }