wake-up-neo.com

MongoDB-Verbindungen von AWS Lambda

Ich bin auf der Suche nach einer RESTful-API mit AWS Lambda/API-Gateway, das mit einer MongoDB-Datenbank verbunden ist. Ich habe gelesen, dass Verbindungen zu MongoDB relativ teuer sind. Daher empfiehlt es sich, eine Verbindung für die Wiederverwendung beizubehalten, sobald die Verbindung hergestellt wurde, anstatt neue Verbindungen für jede neue Abfrage herzustellen.

Dies ist für normale Anwendungen ziemlich unkompliziert, da Sie während des Startens eine Verbindung herstellen und während der Lebensdauer der Anwendung wiederverwenden können. Da Lambda jedoch staatenlos gestaltet werden soll, scheint diese Verbindung weniger einfach zu sein.

Daher frage ich mich, wie Sie dieses Problem mit der Datenbankverbindung am besten lösen könnten. Muss ich jedes Mal neue Verbindungen herstellen, wenn eine Lambda-Funktion aufgerufen wird, oder gibt es eine Möglichkeit, diese Verbindungen für effizientere Abfragen zu bündeln/cachen?

Vielen Dank.

47
Beesknees

AWS-Lambda-Funktionen sollten als zustandslose Funktionen definiert werden, damit sie nicht wie ein Verbindungspool den Status halten können.

Dieses Problem wurde auch in diesem AWS-Forum hervorgehoben. Am 5. Oktober 2015 veröffentlichte AWS-Ingenieur Sean, dass Sie nicht Verbindung für jede Anforderung öffnen und schließen sollten, indem Sie einen Pool für die Code-Initialisierung außerhalb des Handlerblocks erstellen. Aber zwei Tage später veröffentlichte derselbe Ingenieur das das sollten Sie nicht tun.

Das Problem ist, dass Sie die Laufzeitumgebung von Lambda nicht kontrollieren können. Wir wissen, dass diese Umgebungen (oder Container) wiederverwendet werden, wie der Blogpost von Tim Wagner beschreibt. Die mangelnde Kontrolle kann jedoch dazu führen, dass alle Ihre Ressourcen aufgebraucht werden, z. B. das Erreichen eines Verbindungslimits in Ihrer Datenbank. Aber es liegt an dir.

Anstatt von Ihrer Lambda-Funktion aus eine Verbindung zu MongoDB herzustellen, können Sie RESTHeart verwenden, um über HTTP auf die Datenbank zuzugreifen. Der Verbindungspool zu MongoDB wird stattdessen von RESTHeart verwaltet. Denken Sie daran, dass Sie in Bezug auf die Leistung für jede Anforderung eine neue HTTP-Verbindung zu RESTHeart öffnen und keinen HTTP-Verbindungspool verwenden, wie Sie es bei einer herkömmlichen Anwendung tun könnten.

13
tuler

Restheart ist ein REST-basierter Server, der neben MongoDB ausgeführt wird. Es bildet die meisten CRUD-Vorgänge in Mongo für GET, POST usw. ab. Anfragen mit erweiterbarer Unterstützung, wenn Sie einen benutzerdefinierten Handler schreiben müssen (z. B. spezialisierte geoNear-, geoSearch-Abfrage).

5
user1694845

Sie sollten davon ausgehen, dass Lambdas zustandslos sind, aber die Realität ist, dass die VM meistens einfach eingefroren wird und nicht behält einige Zustände. Es wäre dumm für Amazon, für jede Anfrage einen neuen Prozess zu starten, so dass derselbe Prozess häufig wiederverwendet wird, und Sie können diesen Vorteil nutzen, um Verbindungen zu vermeiden.

So vermeiden Sie die Verbindung für jede Anforderung (in Fällen, in denen der Lambda-Prozess erneut verwendet wird):

  1. Schreiben Sie den Handler unter der Annahme, dass der Prozess erneut verwendet wird, sodass Sie eine Verbindung zur Datenbank herstellen und den Lamba den Verbindungspool erneut verwenden (das db-Versprechen, das von MongoClient.connect zurückgegeben wird).

  2. Damit das Lambda nicht warten muss, bis Sie die db-Verbindung geschlossen haben, db.close(), nachdem Sie eine Anfrage bearbeitet haben, sagen Sie ihm, dass es nicht auf eine leere Ereignisschleife warten soll.

Beispiel:

var db = MongoClient.connect(MongoURI);

module.exports.targetingSpec = (event, context, callback) => {
  context.callbackWaitsForEmptyEventLoop = false;
  db.then((db) => {
    // use db
  });
};

Aus der Dokumentation zu context.callbackWaitsForEmptyEventLoop:

callbackWaitsForEmptyEventLoop Der Standardwert ist true. Diese Eigenschaft ist nur nützlich, um das Standardverhalten des Rückrufs zu ändern. Standardmäßig wartet der Rückruf, bis die Node.js-Laufzeitereignisschleife leer ist, bevor der Prozess eingefroren und die Ergebnisse an den Aufrufer zurückgegeben werden. Sie können diese Eigenschaft auf false setzen, um AWS Lambda anzufordern, den Prozess kurz nach dem Aufruf des Callbacks einzufrieren, auch wenn Ereignisse in der Ereignisschleife vorhanden sind. AWS Lambda friert den Prozess, alle Zustandsdaten und die Ereignisse in der Node.js-Ereignisschleife ein (alle verbleibenden Ereignisse in der Ereignisschleife werden verarbeitet, wenn die Lambda-Funktion als nächstes aufgerufen wird und AWS Lambda den eingefrorenen Prozess verwendet). Weitere Informationen zum Rückruf finden Sie unter Verwenden des Rückrufparameters.

3
Tyler Brock

Ich habe einige Tests mit Java-Lambda-Funktionen ausgeführt, die eine Verbindung zu MongoDB Atlas herstellen.

Wie bereits von anderen Postern angegeben, verwendet Amazon die Instances erneut, diese werden jedoch möglicherweise wiederverwertet und das genaue Verhalten kann nicht bestimmt werden. Man könnte also mit alten Verbindungen enden. Ich sammle alle 5 Minuten Daten und schiebe sie alle 5 Minuten in die Lambda-Funktion.

Der Lambda macht im Wesentlichen:

  • Verbindung aufbauen oder wiederverwenden
  • Einen Datensatz abfragen
  • Einen Datensatz schreiben oder aktualisieren
  • verbindung schließen oder offen lassen

Die tatsächliche Datenmenge ist recht gering. Sie variiert je nach Tageszeit zwischen 1 und 5 kB. Ich habe nur 128 MB verwendet.

Die Lambdas liefen in N.Virgina, da dies der Ort ist, an dem die freie Stufe gebunden ist.

Beim Öffnen und Schließen der Verbindung dauern die meisten Anrufe zwischen 4500 und 9000 ms. Bei der Wiederverwendung der Verbindung liegen die meisten Anrufe zwischen 300 und 900 ms. Beim Überprüfen der Atlas-Konsole bleibt die Verbindungsanzahl stabil. Für diesen Fall lohnt sich die Wiederverwendung der Verbindung. Das Herstellen einer Verbindung und sogar das Trennen der Verbindung zu einem Replikatsatz ist mit dem Java-Treiber recht teuer.

Für eine umfangreiche Bereitstellung sollten umfassendere Tests ausgeführt werden.

2
Udo Held

Die kurze Antwort lautet ja, Sie müssen eine neue Verbindung erstellen und sie schließen, bevor das Lambda beendet ist.

Die lange Antwort ist eigentlich während meiner Tests, dass Sie Ihre DB-Verbindungen in Ihrem Handler wie folgt weitergeben können (Beispiel für mysql, da ich es in der Hand habe). Sie können sich nicht darauf verlassen, dass eine Verbindung besteht. Es kann sein, dass, wenn Ihre Lambdas nicht für ewig hingerichtet wurden, sie den Zustand des Handlers verliert (Kaltstart), ich mehr Tests durchführen muss, um herauszufinden, ob ein Lambda viel Verkehr bekommt Mit dem folgenden Beispiel wird keine neue Verbindung erstellt.

// MySQL.database.js
    import * as mysql from 'mysql'

    export default mysql.createConnection({
        Host: 'mysql db instance address',
        user: 'MYSQL_USER',
        password: 'PASSWORD',
        database: 'SOMEDB',
    })

Dann importieren Sie es in Ihrem Handler und geben Sie es an das Lambda weiter, das gerade ausgeführt wird.

// 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

Jetzt in deiner Lambda machst du ...

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()) 


}

Das Responder-Beispiel kann er hier finden. Entschuldigung, es ist ES5, weil dort die Frage gestellt wurde. 

Hoffe das hilft!

0
Mrk Fldig

Leider müssen Sie möglicherweise eine eigene RESTful-API erstellen, um die MongoDB-Anforderungen zu beantworten, bis AWS eine davon erstellt. Bisher haben sie nur das, was Sie für ihre eigene Dynamo DB benötigen.

0
Marin