programing

AWS Lambda에서 MongoDB 연결

lastcode 2023. 5. 22. 21:08
반응형

AWS Lambda에서 MongoDB 연결

AWS Lambda/A를 사용하여 RESTful API를 생성하려고 합니다.PI 게이트웨이가 MongoDB 데이터베이스에 연결되었습니다.MongoDB에 대한 연결은 상대적으로 비용이 많이 들기 때문에 모든 새로운 쿼리에 대해 새 연결을 만드는 것보다 설정한 후에 다시 사용할 수 있도록 연결을 유지하는 것이 가장 좋습니다.

일반 애플리케이션의 경우 시작하는 동안 연결을 설정하고 애플리케이션 수명 동안 다시 사용할 수 있기 때문에 이는 매우 간단합니다.그러나 람다는 상태 비저장 상태로 유지되도록 설계되었기 때문에 이 연결은 덜 직선적인 것처럼 보입니다.

따라서 이 데이터베이스 연결 문제에 접근하는 가장 좋은 방법이 무엇인지 궁금합니다.람다 함수가 호출될 때마다 새 연결을 만들어야 합니까? 아니면 더 효율적인 쿼리를 위해 연결을 풀링/캐시할 수 있는 방법이 있습니까?

감사해요.

AWS Lambda 함수는 상태 비저장 함수로 정의되어야 하므로 연결 풀과 같은 상태를 유지할 수 없습니다.

문제는 이번 AWS 포럼 게시물에서도 제기되었습니다.2015년 10월 5일 AWS 엔지니어 Sean은 코드 초기화 시 핸들러 블록 외부에 풀을 만들어 각 요청에 대한 연결을 열고 닫으면 안 된다고 게시했습니다.하지만 이틀 후에 같은 엔지니어가 당신에게 이것을 하지 말라고 게시했습니다.

문제는 람다의 런타임 환경을 제어할 수 없다는 것입니다.Tim Wagner의 블로그 게시물에 설명된 바와 같이 이러한 환경(또는 컨테이너)은 재사용됩니다.그러나 제어가 부족하면 데이터베이스의 연결 제한에 도달하는 것과 같이 모든 리소스가 소모될 수 있습니다.하지만 그건 당신에게 달렸어요.

람다 함수에서 MongoDB에 연결하는 대신 RESTHeart를 사용하여 HTTP를 통해 데이터베이스에 액세스할 수 있습니다.MongoDB에 대한 연결 풀은 대신 RESTHeart에 의해 유지 관리됩니다.성능과 관련하여 각 요청에 대해 RESTHeart에 대한 새 HTTP 연결을 열 것이며 기존 응용 프로그램에서와 같이 HTTP 연결 풀을 사용하지 않습니다.

람다를 상태 비저장 상태로 가정해야 하지만 실제로는 대부분의 경우 VM이 단순히 동결되어 있고 일부 상태를 유지합니다.Amazon이 모든 요청에 대해 새로운 프로세스를 스핀업하는 것은 비효율적일 것입니다. 따라서 Amazon은 종종 동일한 프로세스를 재사용하며 이를 활용하여 연결을 스레싱하지 않도록 할 수 있습니다.

모든 요청에 대한 연결을 방지하려면(람다 프로세스가 재사용되는 경우):

  1. 풀을 합니다.db에서 돌아온 MongoClient.connect).

  2. db , 람가다 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 런타임 이벤트 루프가 비워질 때까지 기다렸다가 프로세스를 중지하고 결과를 호출자에게 반환합니다.이벤트 루프에 이벤트가 있더라도 콜백이 호출된 직후 AWS Lambda에 프로세스를 중지하도록 요청하려면 이 속성을 false로 설정할 수 있습니다.AWS Lambda는 프로세스, 모든 상태 데이터 및 Node.js 이벤트 루프의 이벤트를 동결합니다(Lambda 함수가 다음에 호출되고 AWS Lambda가 동결된 프로세스를 사용하도록 선택한 경우 이벤트 루프의 나머지 이벤트가 처리됨).콜백에 대한 자세한 내용은 콜백 매개변수 사용을 참조하십시오.

Restheart는 MongoDB와 함께 실행되는 REST 기반 서버입니다.Mongo의 대부분의 CRUD 작업을 사용자 지정 핸들러(예: 전문 지오니어, 지오서치 쿼리)를 작성해야 할 때 확장 가능한 지원이 있는 GET, POST 등의 요청에 매핑합니다.

MongoDB Atlas에 연결된 Java 람다 함수를 실행하여 몇 가지 테스트를 실행했습니다.

이미 다른 포스터에서 언급했듯이 아마존은 인스턴스를 재사용하지만, 이러한 인스턴스는 재활용될 수 있으며 정확한 동작을 결정할 수 없습니다.그래서 연결이 오래될 수 있습니다.나는 5분마다 데이터를 수집하고 5분마다 람다 함수에 푸시하고 있습니다.

람다는 기본적으로 다음을 수행합니다.

  • 연결 구축 또는 재사용
  • 하나의 레코드 쿼리
  • 하나의 레코드 쓰기 또는 업데이트
  • 연결을 닫거나 열어 둡니다.

실제 데이터 양은 상당히 적습니다.하루 중 시간에 따라 1 - 5kB의 차이가 있습니다.128MB밖에 안 썼어요.

람다는 N에서 달렸습니다.버지니아는 자유 계층이 묶이는 위치입니다.

연결을 열고 닫을 때마다 대부분의 통화는 4500 - 9000ms 사이입니다.연결을 재사용할 때 대부분의 통화는 300 - 900ms 사이입니다.Atlas 콘솔을 확인하면 연결 수가 안정적으로 유지됩니다.이 경우 연결을 다시 사용할 가치가 있습니다.Java 드라이버를 사용하면 연결을 구축하고 복제본 집합에서 연결을 끊는 데도 비용이 많이 듭니다.

대규모 배포의 경우 보다 포괄적인 테스트를 실행해야 합니다.

대한 을 캐시/connection입니다. ", MongoDB", "MongoDB"는할 수 .: "MongoDB"와 같이 사용할 수 있습니다.
하십시오.
AWS 람다 Mongoose 사용
AWS Lambda 최적화(조금 오래됨)

const mongoose = require('mongoose');

let conn = null;

const uri = 'YOUR CONNECTION STRING HERE';

exports.handler = async function(event, context) {
  // Make sure to add this so you can re-use `conn` between function calls.
  context.callbackWaitsForEmptyEventLoop = false;

  const models = [{name: 'User', schema: new mongoose.Schema({ name: String })}]
  conn = await createConnection(conn, models)
  //e.g.
  const doc = await conn.model('User').findOne({})
  console.log('doc: ', doc);
};

const createConnection = async (conn,models) => {
  // Because `conn` is in the global scope, Lambda may retain it between
  // function calls thanks to `callbackWaitsForEmptyEventLoop`.
  // This means your Lambda function doesn't have to go through the
  // potentially expensive process of connecting to MongoDB every time.

    if (conn == null || (conn && [0, 3].some(conn.readyState))) {
        conn = await mongoose.createConnection(uri, {
        // Buffering means mongoose will queue up operations if it gets
        // disconnected from MongoDB and send them when it reconnects.
        // With serverless, better to fail fast if not connected.
          bufferCommands: false, // Disable mongoose buffering
          bufferMaxEntries: 0, // and MongoDB driver buffering
          useNewUrlParser: true,
          useUnifiedTopology: true,
          useCreateIndex: true
        })
        for (const model of models) {
          const { name, schema } = model
          conn.model(name, schema)
        }
      }
  
      return conn
  }

안타깝게도 AWS가 MongoDB 요청에 응답하기 위해 자체 RESTful API를 만들어야 할 수도 있습니다.지금까지 그들은 그들만의 Dynamo DB에 필요한 것만 가지고 있습니다.

간단한 대답은 예입니다. 람다가 완료되기 전에 새 연결을 만들고 닫아야 합니다.

긴 대답은 실제로 테스트 중에 처리기에서 DB 연결을 전달할 수 있다는 것입니다. (내가 처리해야 하는 mysql 예제) 연결이 있는 것에 의존할 수 없으므로 아래의 예를 확인하십시오. 람다가 오랫동안 실행되지 않으면 처리기에서 상태가 손실될 수 있습니다(콜드 스타트).확인하려면 더 많은 테스트를 수행해야 하지만 아래 예제를 사용하여 람다의 트래픽이 많은지 확인했습니다. 새 연결이 생성되지 않습니다.

// 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가 질문을 받은 곳이기 때문입니다.

이것이 도움이 되길 바랍니다!

AWS Lambda에서 연결을 위한 공식 모범 사례

AWS Lambda 핸들러 함수 외부의 MongoDB 서버에 대한 클라이언트를 정의해야 합니다.함수를 호출할 때마다 새 MongoClient 개체를 정의하지 마십시오.이렇게 하면 드라이버가 각 함수 호출과 함께 새 데이터베이스 연결을 만듭니다.이는 비용이 많이 들 수 있으며 응용프로그램이 데이터베이스 연결 제한을 초과할 수 있습니다.

또는 다음을 수행합니다.

  1. MongoClient 개체를 한 번 만듭니다.
  2. 함수 호출에서 함수가 MongoClient를 재사용할 수 있도록 개체를 저장합니다.

1단계

에 대한 통화를 격리합니다.MongoClient.connect()기능을 자체 모듈로 변환하여 여러 기능 간에 연결을 재사용할 수 있습니다.파일을 생성합니다.mongo-client.js이를 위해:

mongo-client.js:

const { MongoClient } = require('mongodb');

// Export a module-scoped MongoClient promise. By doing this in a separate
// module, the client can be shared across functions.
const client = new MongoClient(process.env.MONGODB_URI);

module.exports = client.connect();

2단계

새 모듈을 가져와 함수 처리기에서 사용하여 데이터베이스에 연결합니다.

some-file.js:

const clientPromise = require('./mongodb-client');

// Handler
module.exports.handler = async function(event, context) {
  // Get the MongoClient by calling await on the connection promise. Because
  // this is a promise, it will only resolve once.
  const client = await clientPromise;
  
  // Use the connection to return the name of the connected database for example.
  return client.db().databaseName;
}

자원.

자세한 내용은 이 문서를 참조하십시오.

우리는 1분마다 자체 관리되는 MongoDB에 연결되는 AWS 람다를 테스트했습니다.

연결이 불안정하여 람다가 실패했습니다.

MongoDB를 Nginx 역방향 프록시 스트림 모듈로 래핑하여 이 문제를 해결했습니다.

Nginx Reverse Proxy 뒤에 MongoDB를 설정하는 방법

stream {
    server {
        listen  <your incoming Mongo TCP port>;
        proxy_connect_timeout 1s;
        proxy_timeout 3s;
        proxy_pass    stream_mongo_backend;
    }

    upstream stream_mongo_backend {
      server <localhost:your local Mongo TCP port>;
  }
}

재사용을 위해 연결을 저장하는 것 외에도 람다 함수에 대한 메모리 할당을 늘립니다.AWS는 메모리 할당에 비례하여 CPU를 할당하며, 128MB에서 1.5Gb로 변경하면 mongodbatlas에 연결할 때 연결 시간이 4초에서 0.5초로 단축됩니다.

여기서 더 읽기: https://aws.amazon.com/lambda/faqs/

저는 몇 번 전에 같은 문제에 직면했지만 EC2의 동일한 계정에 제 몽고를 올려놓음으로써 해결했습니다.저는 제 람다 함수가 있는 AWS EC2 계정에 몽고 DB를 만들었습니다.

이제 개인 IP로 람다 함수에서 내 몽고에 액세스할 수 있습니다.

언급URL : https://stackoverflow.com/questions/31728414/mongodb-connections-from-aws-lambda

반응형