MongoDBデータベースに接続されたAWS Lambda/API Gatewayを使用してRESTful APIを作成したいと考えています。 MongoDBへの接続は比較的高価であるため、新しいクエリごとに新しい接続を作成するのではなく、一度確立された再利用のために接続を保持することをお勧めします。
これは、起動時に接続を確立し、アプリケーションの有効期間中に再利用できるため、通常のアプリケーションでは非常に簡単です。しかし、Lambdaはステートレスであるように設計されているため、この接続はそれほど簡単ではないようです。
したがって、このデータベース接続の問題に対処する最善の方法は何だろうと思いますか? Lambda関数が呼び出されるたびに新しい接続を強制されますか、またはこれらの接続をより効率的なクエリのためにプール/キャッシュする方法はありますか?
ありがとう。
AWS Lambda関数はステートレス関数として定義する必要があるため、接続プールのような状態を保持できません。
この問題は、この AWSフォーラム投稿 でも発生しました。 2015年10月5日に、AWSエンジニアのショーンは、ハンドラーブロックの外側でコードの初期化時にプールを作成することにより、各リクエストで接続を not する必要があると投稿しました。しかし、2日後、同じエンジニアがこれを行うべきではないことを投稿しました。
問題は、Lambdaのランタイム環境を制御できないことです。 Tim Wagnerによるブログ投稿 で説明されているように、これらの環境(またはコンテナ)が再利用されることはわかっています。しかし、制御が不足していると、データベースの接続制限に達するなど、すべてのリソースを消費することになります。しかし、それはあなた次第です。
ラムダ関数からMongoDBに接続する代わりに、 RESTHeart を使用してHTTP経由でデータベースにアクセスできます。 MongoDBへの接続プールは、代わりにRESTHeartによって維持されます。パフォーマンスに関しては、要求ごとにRESTHeartへの新しいHTTP接続を開き、従来のアプリケーションで実行できるようにHTTP接続プールを使用しないことに注意してください。
Restheart は、MongoDBと一緒に実行されるRESTベースのサーバーです。 MongoのほとんどのCRUD操作をGET、POSTなどにマッピングします。カスタムハンドラー(特殊なgeoNear、geoSearchクエリなど)を記述する必要がある場合は、拡張可能なサポートを使用してリクエストします。
ラムダはステートレスであると仮定する必要がありますが、現実には、ほとんどの場合、vmは単にフリーズされ、does維持some状態。 Amazonがすべてのリクエストに対して新しいプロセスを起動するのは愚かなことなので、彼らはしばしば同じプロセスを再利用し、これを利用して接続のスラッシングを回避できます。
すべてのリクエストで接続を回避するには(ラムダプロセスが再利用される場合):
データベースに接続し、Lambaが接続プールを再利用するようにプロセスが再利用されることを前提にハンドラーを記述します(MongoClient.connect
から返されるdb
約束)。
要求を処理した後、ラムダがデータベース接続を閉じるのを待ってハングアップしないようにするために、db.close()
は空のイベントループを待たないように指示します。
例:
var db = MongoClient.connect(MongoURI);
module.exports.targetingSpec = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
db.then((db) => {
// use db
});
};
context.callbackWaitsForEmptyEventLoop
に関するドキュメントから:
callbackWaitsForEmptyEventLoopデフォルト値はtrueです。このプロパティは、コールバックのデフォルトの動作を変更する場合にのみ役立ちます。デフォルトでは、コールバックはNode.jsランタイムイベントループが空になるまで待機してからプロセスをフリーズし、結果を呼び出し元に返します。このプロパティをfalseに設定すると、イベントループにイベントがある場合でも、コールバックが呼び出された直後にプロセスをフリーズするようAWS Lambdaにリクエストできます。 AWS Lambdaは、Node.jsイベントループ内のプロセス、状態データ、およびイベントを凍結します(イベントループ内の残りのイベントは、Lambda関数が次に呼び出され、AWS Lambdaが凍結プロセスの使用を選択した場合に処理されます)。コールバックの詳細については、「コールバックパラメーターの使用」を参照してください。
MongoDB Atlasに接続するJava Lambda関数を実行するいくつかのテストを実行しました。
他のポスターで既に述べたように、Amazonはインスタンスを再利用しますが、これらはリサイクルされる可能性があり、正確な動作を判断することはできません。そのため、接続が古くなる可能性があります。 5分ごとにデータを収集し、5分ごとにLambda関数にプッシュします。
Lambdaは基本的に次のことを行います。
実際のデータ量は非常に少ないです。時刻に応じて、1〜5 kBの範囲で変化します。 128 MBのみを使用しました。
これは 無料利用枠 が関連付けられている場所であるため、ラムダはN.Virginaで実行されました。
ほとんどの通話が4500〜9000ミリ秒かかるたびに接続を開いたり閉じたりするとき。接続を再利用する場合、ほとんどの呼び出しは300〜900ミリ秒です。 Atlasコンソールを確認すると、接続カウントは安定しています。この場合、接続を再利用する価値があります。 Javaドライバーを使用すると、接続を構築し、レプリカセットから切断することでも、かなりの費用がかかります。
大規模な展開では、より包括的なテストを実行する必要があります。
短い答えはイエスです。新しい接続を作成し、ラムダが終了する前にそれを閉じる必要があります。
長い答えは実際には私のテスト中にあなたのハンドラーでDB接続を渡すことができます(mysqlの例は私が手に入れたものです)、あなたはこれに接続があることに頼ることができないので以下の私の例を確認してください、 Lambdaが長い間実行されていない場合、ハンドラーから状態が失われる可能性があります(コールドスタート)、見つけるためにさらにテストを行う必要がありますが、Lambdaが大量のトラフィックを取得している場合、以下の例を使用すると、新しい接続は作成されません。
// MySQL.database.js
import * as mysql from 'mysql'
export default mysql.createConnection({
Host: 'mysql db instance address',
user: 'MYSQL_USER',
password: 'PASSWORD',
database: 'SOMEDB',
})
次に、ハンドラーでそれをインポートし、実行中のラムダに渡します。
// handler.js
import MySQL from './MySQL.database.js'
const funcHandler = (func) => {
return (event, context, callback) => {
func(event, context, callback, MySQL)
}
}
const handler = {
someHandler: funcHandler(someHandler),
}
export default handler
今、あなたのラムダであなたは...
export default (event, context, callback, MySQL) => {
context.callbackWaitsForEmptyEventLoop = false
// Check if their is a MySQL connection if not, then open one.
// Do ya thing, query away etc etc
callback(null, responder.success())
}
レスポンダーの例は、彼が見つけることができます こちら 申し訳ありませんがES5が質問された場所だからです。
お役に立てれば!
残念ながら、独自のRESTful APIを作成して、AWSが出すまでMongoDBリクエストに応答する必要がある場合があります。これまでのところ、Dynamo DBに必要なものしか持っていません。