为什么建议不要在 Node.js 代码中的任何地方关闭 MongoDB 连接?

请考虑以下 Node.js 代码:

function My_function1(_params) {
db.once('open', function (err){
//Do some task 1
});
}


function My_function2(_params) {
db.once('open', function (err){
//Do some task 2
});
}

请参阅最佳实践的链接,其中说不要关闭任何连接

Https://groups.google.com/forum/#!topic/node-mongodb-native/5cpt84tusvg

我看到日志文件包含以下数据:

Fri Jan 18 11:00:03 Trying to start Windows service 'MongoDB'
Fri Jan 18 11:00:03 Service running
Fri Jan 18 11:00:03 [initandlisten] MongoDB starting : pid=1592 port=27017 dbpath=\data\db\ 64-bit host=AMOL-KULKARNI
Fri Jan 18 11:00:03 [initandlisten] db version v2.2.1, pdfile version 4.5
Fri Jan 18 11:00:03 [initandlisten] git version: d6...e0685521b8bc7b98fd1fab8cfeb5ae
Fri Jan 18 11:00:03 [initandlisten] build info: windows sys.getwindowsversion(major=6, minor=1, build=7601, platform=2, service_pack='Service Pack 1') BOOST_LIB_VERSION=1_49
Fri Jan 18 11:00:03 [initandlisten] options: { config: "c:\mongodb\mongod.cfg", logpath: "c:\mongodb\log\mongo.log", service: true }
Fri Jan 18 11:00:03 [initandlisten] journal dir=/data/db/journal
Fri Jan 18 11:00:03 [initandlisten] recover begin
Fri Jan 18 11:00:04 [initandlisten] recover lsn: 6624179
Fri Jan 18 11:00:04 [initandlisten] recover /data/db/journal/j._0
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section seq:59343 < lsn:6624179
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section seq:118828 < lsn:6624179
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section seq:238138 < lsn:6624179
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section seq:835658 < lsn:6624179
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section seq:955218 < lsn:6624179
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section seq:3467218 < lsn:6624179
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section seq:3526418 < lsn:6624179
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section seq:3646154 < lsn:6624179
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section seq:3705844 < lsn:6624179
Fri Jan 18 11:00:04 [initandlisten] recover skipping application of section more...
Fri Jan 18 11:00:05 [initandlisten] recover cleaning up
Fri Jan 18 11:00:05 [initandlisten] removeJournalFiles
Fri Jan 18 11:00:05 [initandlisten] recover done
Fri Jan 18 11:00:10 [initandlisten] query MYDB.system.namespaces query: { options.temp: { $in: [ true, 1 ] } } ntoreturn:0 ntoskip:0 nscanned:5 keyUpdates:0  nreturned:0 reslen:20 577ms
Fri Jan 18 11:00:10 [initandlisten] waiting for connections on port 27017
Fri Jan 18 11:00:10 [websvr] admin web console waiting for connections on port 28017
Fri Jan 18 11:01:10 [PeriodicTask::Runner] task: WriteBackManager::cleaner took: 32ms
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50076 #1 (1 connection now open)
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50077 #2 (2 connections now open)
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50078 #3 (3 connections now open)
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50079 #4 (4 connections now open)
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50080 #5 (5 connections now open)
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50081 #6 (6 connections now open)
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50082 #7 (7 connections now open)
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50083 #8 (8 connections now open)
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50084 #9 (9 connections now open)
Fri Jan 18 13:36:27 [initandlisten] connection accepted from 192.168.0.1:50085 #10 (10 connections now open)
...........................................
Fri Jan 18 13:36:48 [initandlisten] connection accepted from 192.168.0.1:50092 #97 (97 connections now open)

这不会因为打开多个连接而不关闭它而在服务器上造成开销吗? 它在内部处理连接池吗?

但是在 MongoDB 文档中提到“这是不使用请求池的应用程序的正常行为”

谁能告诉我。

105609 次浏览

我不是 node.js 专家,但是我认为大多数语言之间的原因是相对相同的。

建立联系是:

这是司机做的最重要的事情之一。即使在高速网络上,正确建立一个连接也需要几百毫秒。

(http://php.net/manual/en/mongo.connecting.pools.php)

假设这是为 PHP 和文档是一个有点过时的部分仍然适用,即使现在和跨大多数,如果不是全部,驱动程序。

每个连接还可以使用单独的线程,这会导致明显的开销。

它似乎来自:

Http://mongodb.github.com/node-mongodb-native/driver-articles/mongoclient.html#the-url-connection-format

Js 仍然使用连接池来尝试停止建立连接的开销。当然,这不再适用于 PHP 这样的其他驱动程序。

它打开到数据库服务器的 x数量的连接(默认是 5) ,并在需要数据时将工作传输到一个空闲连接,因此重用旧的连接可以避免这种可能导致这些日志的讨厌的进程:

Https://docs.mongodb.com/manual/faq/diagnostics/#why-does-mongodb-log-so-many-connection-accepted-events

使用 MongoClient 打开一个 Db 连接,并在整个应用程序中重用它。如果需要使用多个数据库,请使用。函数使用相同的底层连接池处理不同的 Db。保留池是为了确保单个阻塞操作不会冻结您的 node.js 应用程序。如果池中有5个连接,则为默认大小。

Http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html

我还忘了加上。正如另一个答案所指出的,建立一个新的 TCP 连接在时间和内存方面都很昂贵,这就是为什么要重用连接的原因。此外,一个新的连接将导致在 MongoDB 上使用数据库上的内存创建一个新的线程。

MongoDB 池数据库连接的效率更高,因此在 monGodb.log 中打开许多连接并不罕见

然而,当你的应用程序完全关闭时,关闭所有连接是有用的。这段代码非常适合这样做。

process.on('SIGINT', function() {
mongoose.connection.close(function () {
console.log('Mongoose disconnected on app termination');
process.exit(0);
});
});

如果你想确保 mongo 在程序终止时断开连接,以及在程序运行期间只建立一个连接,我建议编写以下单例(不幸的是,这是在 python 中,而不是在 node 中,但同样的概念适用)。

import atexit


class MongoDB:
'''define class attributes'''
__instance = None


@staticmethod
def getInstance():
""" Static access method. """
# if the instance doesnt exist envoke the constructor
if MongoDB.__instance == None:
MongoDB()
# return instance
return MongoDB.__instance


def __init__(self) -> None:
""" Virtually private constructor. """
if MongoDB.__instance != None:
raise Exception("Singleton cannot be instantiated more than once")


else:
print("Creating MongoDB connection")
# set instance and instance attributes
self.client = MongoClient(config.CONNECTION_STRING)
MongoDB.__instance = self




@staticmethod
@atexit.register
def closeConnection():
'''
Python '__del__' aka destructor dunder doesnt always get called
mainly when program is terminated by ctrl-c so this method is decorated
by 'atexit' which ensures this method is called upon program termination
'''
if MongoDB.__instance != None:
MongoDB.__instance.client.close()
print("Closing Connections")

我认为这是一个很好的设计模式,可以确保所有连接在程序结束时断开连接,连接的同一个实例被共享,并且只建立一次,因为之前有人声明连接到数据库是应该避免的最昂贵的任务