source

MongoDB에 안정적으로 다시 연결

lovecheck 2023. 7. 1. 09:00
반응형

MongoDB에 안정적으로 다시 연결

업데이트: 드라이버에서 3.2에 대해 2.1 버전을 사용하고 있습니다.

MongoDB를 사용하는 노드 애플리케이션이 있습니다.제가 가지고 있는 문제는 어떤 이유로든 MongoDB 서버가 다운되면 애플리케이션이 다시 연결되지 않습니다.이 문제를 해결하기 위해, 저는 공식적인 튜토리얼의 코드를 기반으로 테스트를 진행했습니다.

var MongoClient = require('mongodb').MongoClient
  , f = require('util').format;

MongoClient.connect('mongodb://localhost:27017/test', 

// Optional: uncomment if necessary
// { db: { bufferMaxEntries: 3 } },


function(err, db) {
  var col = db.collection('t');

  setInterval(function() {
    col.insert({a:1}, function(err, r) {
      console.log("insert")
      console.log(err)

      col.findOne({}, function(err, doc) {
        console.log("findOne")
        console.log(err)
      });
    })
  }, 1000)
});

이 스크립트를 실행한 다음 mongod를 중지하고 다시 시작하는 것입니다.자, 이제 시작합니다.

테스트 1: mongod를 10초간 정지시킵니다.

MongoDb를 10초 동안 중지하면 원하는 결과가 나옵니다. 10초 동안 쿼리 실행을 중지하고 서버가 back ip가 되면 쿼리를 모두 실행합니다.

테스트 2: mongod를 30초 동안 정지

정확히 30초 후에 다음 메시지가 표시됩니다.

{ [MongoError: topology was destroyed] name: 'MongoError', message: 'topology was destroyed' }
insert

{ [MongoError: topology was destroyed] name: 'MongoError', message: 'topology was destroyed' }

문제는 지금부터 mongod를 다시 시작하면 연결이 다시 설정되지 않는다는 것입니다.

해결책?

이 문제에 해결책이 있습니까?만약 그렇다면, 여러분은 그것이 무엇인지 알고 있나요?일단 내 앱이 "topology was destropped"를 토하기 시작하면, 모든 것을 다시 작동시키는 유일한 방법은 전체 앱을 다시 시작하는 것입니다.

연결 실패 후 mongo nodejs 드라이버를 다시 연결하는 방법을 제어하는 두 가지 연결 옵션이 있습니다.

  • reconnectTries: 재연결 시도 횟수(기본값 30회)
  • 다시 연결간격:서버가 재시도 간격(기본값 1000ms) 동안 대기합니다.

mongo 드라이버 문서에 대한 참조

즉, mongo는 기본적으로 30번 연결을 계속 시도하고 재시도할 때마다 1초 동안 기다립니다.그렇기 때문에 30초 후에 오류가 나타나기 시작합니다.

당신은 이 샘플과 같이 당신의 필요에 따라 이 2개의 파라미터를 수정해야 합니다.

var MongoClient = require('mongodb').MongoClient,
    f = require('util').format;

MongoClient.connect('mongodb://localhost:27017/test', 
    {
        // retry to connect for 60 times
        reconnectTries: 60,
        // wait 1 second before retrying
        reconnectInterval: 1000
    },

    function(err, db) {
        var col = db.collection('t');

        setInterval(function() {
            col.insert({
                a: 1
            }, function(err, r) {
                console.log("insert")
                console.log(err)

                col.findOne({}, function(err, doc) {
                    console.log("findOne")
                    console.log(err)
                });
            })
        }, 1000)
    });

기본 30번 대신 60번 시도합니다. 즉, 60초 후에 다시 연결 시도가 중지되면 오류가 표시됩니다.

. : " / 청 요 이 참 앱 때 기 는 리 려 면 방 하 합 지 다 통 야 니 옵 을 고 션 해 과 것 다 을 연 지 시 다 까 기 만 결 료 될 간 이 ▁the ▁option / ▁sid ▁if ▁pass ▁from ▁to 참 : en request ▁app ▁you ▁have 요 ▁the ▁untilbufferMaxEntries: 0이에 대한 대가는 짧은 네트워크 중단 동안에도 요청이 중단된다는 것입니다.

json:"mongodb": "3.1.3"

기존 연결 다시 연결

설정된에 대한 하려면 미설정연된연결구미면조려를 할 수 .reconnectTries/reconnectInterval옵션(기본값여기서 추가 설명서)을 참조하십시오.

초기 연결 다시 연결

초기 연결의 경우 오류가 발생하면 mongo 클라이언트가 다시 연결되지 않습니다(아래 참조).그렇게 해야 한다고 생각하지만, 그 사이에 라이브러리를 사용하여 다음과 같은 해결 방법을 만들었습니다(지수적 백오프 전략 사용).

const promiseRetry = require('promise-retry')
const MongoClient = require('mongodb').MongoClient

const options = {
  useNewUrlParser: true,
  reconnectTries: 60,
  reconnectInterval: 1000,
  poolSize: 10,
  bufferMaxEntries: 0
}

const promiseRetryOptions = {
  retries: options.reconnectTries,
  factor: 1.5,
  minTimeout: options.reconnectInterval,
  maxTimeout: 5000
}

const connect = (url) => {
  return promiseRetry((retry, number) => {
    console.log(`MongoClient connecting to ${url} - retry number: ${number}`)
    return MongoClient.connect(url, options).catch(retry)
  }, promiseRetryOptions)
}

module.exports = { connect }

Mongo 초기 연결 오류: failed to connect to server [db:27017] on first connect

기본적으로 Mongo 드라이버는 초당 하나씩 30번 재연결을 시도합니다.그런 다음 다시 연결을 시도하지 않습니다.

재시도 횟수를 Number.MAX_VALUE로 설정하여 "거의 영원히" 다시 연결되도록 할 수 있습니다.

    var connection = "mongodb://127.0.0.1:27017/db";
    MongoClient.connect(connection, {
      server : {
        reconnectTries : Number.MAX_VALUE,
        autoReconnect : true
      }
    }, function (err, db) {

    });

mongodb 드라이버 3.1.10을 사용하여 다음과 같이 연결을 설정할 수 있습니다.

MongoClient.connect(connectionUrl, {
    reconnectInterval: 10000, // wait for 10 seconds before retry
    reconnectTries: Number.MAX_VALUE, // retry forever
}, function(err, res) {
    console.log('connected') 
})

지정할 필요가 없습니다.autoReconnect: true기본값이기 때문입니다.

연결 재시도 제한을 초과했을 수 있기 때문에 발생한 것입니다.재시도 횟수가 많으면 TCP 연결이 끊어지고 유휴 상태가 됩니다.따라서 재시도 횟수를 늘리고 연결 재시도 간격을 늘리는 것이 좋습니다.

아래 옵션 사용:

retryMiliSeconds {Number, default:5000}, number of milliseconds between retries.
numberOfRetries {Number, default:5}, number of retries off connection.

자세한 내용은 이 링크 https://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html 를 참조하십시오.

솔루션:

MongoClient.connect("mongodb://localhost:27017/integration_test_?", {
    db: {
      native_parser: false,
retryMiliSeconds: 100000,
numberOfRetries: 100
    },
    server: {
      socketOptions: {
        connectTimeoutMS: 500
      }
    }
  }, callback)

드라이버 버전에 따라 동작이 다를 수 있습니다.드라이버 버전을 언급해야 합니다.

드라이버 버전 : 2.2.10 (하드웨어) mongob 버전 : 3.0.7

아래 코드는 mongod가 다시 작동하는 데 걸리는 시간을 연장합니다.

var MongoClient = require('mongodb').MongoClient
  , f = require('util').format;

function connectCallback(err, db) {
  var col = db.collection('t');

  setInterval(function() {
    col.insert({a:1}, function(err, r) {
      console.log("insert")
      console.log(err)

      col.findOne({}, function(err, doc) {
        console.log("findOne")
        console.log(err)
      });
    })
  }, 1000)
}
var options = { server: { reconnectTries: 2000,reconnectInterval: 1000 }} 
MongoClient.connect('mongodb://localhost:27017/test',options,connectCallback);

두 번째 인수를 사용하여 서버 옵션을 전달할 수 있습니다.

만약 당신이 당신의 스키마에 Mongoose를 사용하고 있었다면, mongoose는 첫 번째 시도가 실패한 후에 절대로 mongoDB에 다시 연결하려고 시도하지 않았기 때문에 아래의 나의 옵션을 고려할 가치가 있습니다.

MongoDB API를 위해 Azure CosmosDB에 연결합니다.당신의 것은 아마도 로컬 기계에 있을 것입니다.

아래는 제 코드입니다.

const mongoose = require('mongoose');

// set the global useNewUrlParser option to turn on useNewUrlParser for every connection by default.
mongoose.set('useNewUrlParser', true);
// In order to use `findOneAndUpdate()` and `findOneAndDelete()`
mongoose.set('useFindAndModify', false);

async function mongoDbPool() {
// Closure.
return function connectWithRetry() {
    // All the variables and functions in here will Persist in Scope.
    const COSMODDBUSER = process.env.COSMODDBUSER;
    const COSMOSDBPASSWORD = process.env.COSMOSDBPASSWORD;
    const COSMOSDBCONNSTR = process.env.COSMOSDBCONNSTR;

    var dbAuth = {
        auth: {
            user: COSMODDBUSER,
            password: COSMOSDBPASSWORD
        }
    };
    const mongoUrl = COSMOSDBCONNSTR + '?ssl=true&replicaSet=globaldb';

    return mongoose.connect(mongoUrl, dbAuth, (err) => {
        if (err) {
            console.error('Failed to connect to mongo - retrying in 5 sec');
            console.error(err);
            setTimeout(connectWithRetry, 5000);
        } else {
            console.log(`Connected to Azure CosmosDB for MongoDB API.`);
        }
    });
};}

종속성 주입을 통해 DB에 연결해야 하는 모든 곳에서 이 모듈을 내보내고 재사용할 수 있습니다.그러나 지금은 데이터베이스 연결에 액세스하는 방법만 보여드리겠습니다.

(async () => {
    var dbPools = await Promise.all([mongoDbPool()]);
    var mongoDbInstance = await dbPools[0]();

    // Now use "mongoDbInstance" to do what you need.
})();

언급URL : https://stackoverflow.com/questions/39785036/reliably-reconnect-to-mongodb

반응형