提问人:Merc 提问时间:9/30/2016 最后编辑:Merc 更新时间:9/24/2019 访问量:43353
可靠地重新连接到 MongoDB
Reliably reconnect to MongoDB
问:
更新:我在驱动程序上使用 2.1 版本,而不是 3.2
我有一个使用 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 秒内停止运行查询,然后在服务器返回 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时,连接不会重新建立。
解决 方案?
这个问题有解决方案吗?如果是这样,你知道它是什么吗? 一旦我的应用程序开始吐出“拓扑被破坏”,让一切恢复正常的唯一方法是重新启动整个应用程序......
答:
有 2 个连接选项可以控制连接失败后 mongo nodejs 驱动程序如何重新连接
- reconnect尝试:尝试重新连接 #times(默认 30 次)
- reconnectInterval:服务器将在重试之间等待 # 毫秒 (默认值为 1000 毫秒)
这意味着 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)
});
这将尝试 60 次,而不是默认的 30 次,这意味着当它停止尝试重新连接时,您将在 60 秒后开始看到错误。
旁注:如果要防止应用程序/请求等到重新连接期限到期,则必须通过选项。这样做的代价是,在短暂的网络中断期间,请求也会中止。bufferMaxEntries: 0
评论
{ server: ... }
{server: ...}
server:{ ... }
不同版本的驱动程序的行为可能有所不同。您应该提及您的驱动程序版本。
驱动程序版本 : 2.2.10 (最新) MONGO DB版本: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);
第二个参数可用于传递服务器选项。
评论
{ server: ... }
{server: ...}
server:
默认情况下,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) {
});
发生这种情况是因为它可能已超过重试连接限制。重试次数后,它会破坏 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)
package.json:"mongodb": "3.1.3"
重新连接现有连接
要微调预先建立的连接的重新连接配置,您可以修改 / 选项(默认值和更多文档,请参阅此处)。reconnectTries
reconnectInterval
重新连接初始连接
对于初始连接,如果遇到错误,mongo 客户端不会重新连接(见下文)。我相信它应该,但与此同时,我使用 promise-retry
库(使用指数回退策略)创建了以下解决方法。
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
评论
client
Promise.then
async
await
client
MongoClient.connect
使用 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
如果您将 Mongoose 用于您的模式,那么值得考虑我在下面的选择,因为 mongoose 在第一次尝试失败后从未重新尝试隐式重新连接到 mongoDB。
请注意,我正在连接到 Azure CosmosDB for MongoDB API。在你的机器上,也许在本地机器上。
下面是我的代码。
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.`);
}
});
};}
您可以决定在需要通过依赖注入连接到数据库的任何地方导出和重用此模块。但是,我现在只展示如何访问数据库连接。
(async () => {
var dbPools = await Promise.all([mongoDbPool()]);
var mongoDbInstance = await dbPools[0]();
// Now use "mongoDbInstance" to do what you need.
})();
评论