应用程序和MongoDB运行时,数据量在100M以内,系统运行3天左右后,MongoDB报OOM的错误并退出。
使用环境:
异常信息:
2019-05-09T19:20:44.186+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\util\stacktrace_windows.cpp(239) mongo::printStackTrace+0x43
2019-05-09T19:20:44.186+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\util\signal_handlers_synchronous.cpp(332) mongo::reportOutOfMemoryErrorAndExit+0x90
2019-05-09T19:20:44.186+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\util\allocator.cpp(51) mongo::mongoRealloc+0x19
2019-05-09T19:20:44.186+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\bson\util\builder.h(332) mongo::_BufBuilder::grow_reallocate+0x195
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\rpc\legacy_reply_builder.cpp(84) mongo::rpc::LegacyReplyBuilder::getInPlaceReplyBuilder+0x31
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\db\commands\dbcommands.cpp(1486) mongo::Command::run+0xa7
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\db\commands\dbcommands.cpp(1443) mongo::Command::execCommand+0xb9d
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\db\run_commands.cpp(73) mongo::runCommands+0x4e4
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\db\instance.cpp(236) mongo::`anonymous namespace'::receivedCommand+0x1d4
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\db\instance.cpp(614) mongo::assembleResponse+0x7ba
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\db\service_entry_point_mongod.cpp(135) mongo::ServiceEntryPointMongod::_sessionLoop+0x159
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(212) std::_Func_impl<,std::allocator,void,std::shared_ptr const & __ptr64>::_Do_call+0x43
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe ...\src\mongo\transport\service_entry_point_utils.cpp(78) mongo::`anonymous namespace'::runFunc+0x1b3
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(247) std::_LaunchPad >,std::default_delete > > > >::_Run+0x75
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] mongod.exe c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(210) std::_Pad::_Call_func+0x9
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] ucrtbase.dll o_strcat_s+0x5e
2019-05-09T19:20:44.187+0800 I CONTROL [conn59] KERNEL32.DLL BaseThreadInitThunk+0x14
2019-05-09T19:20:44.187+0800 F - [conn59] out of memory.
我重复了链接2的实验及验证其结果。将MongoDB的 Internal cache设置为256M,MongoDB在一个星期内没有发生过崩溃的情况。
实验配置如下:
systemLog:
destination: file
path: "D:\\db.log"
logAppend: true
storage:
dbPath: "D:\\db"
directoryPerDB: true
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 0.256
net:
bindIp: 127.0.0.1
port: 27017
security:
authorization: disabled
MongoDB的Internal cache可通过--wiredTigerCacheSizeGB或者上述配置设置Internal cache的大小。
MongoDB使用内存的方式不是从实例一开始就向操作系统申请了好了足够的内存空间,而是在运行的过程中,逐渐向操作系统申请内存的。例如,将Internal cache的大小设置为3G,而mongod实例刚启动时,它使用的内存仅有几十M或几百M。
因此,MongoDB在运行过程中,会不停的向操作系统申请内存空间,直到涨到设置的最大值。然而,应用程序向操作系统申请内存是产生OOM的主要原因,存在与其它程序抢占资源或者在操作系统安全策略下不给申请内存的风险。
导致MongoDB崩溃的代码如下:
类:allocator.cpp
源码函数:
void* mongoRealloc(void* ptr, size_t size) {
void* x = std::realloc(ptr, size);
if (x == NULL) {
reportOutOfMemoryErrorAndExit();
}
return x;
}
那么降低Internal cache的大小能避免MongoDB运行崩溃,是因为其操作在一定程度上避免了DB向操作系统申请更多的内存,仅在原有的内存空间重新分配内存。
如果为了MongoDB不崩溃,把Internal cache设置在少量内存空间下运行,同样是不合理的,毕竟MongoDB是依靠大量的内存提高计算速率的。
首先,应该先了解下MongoDB的wiredTiger的使用内存情况。
MongoDB 使用Internal cache 和 Filesystem cache两部分内存。
默认的,Internal cache 取以下两个值的最大值:
50% of (RAM - 1 GB), or
256 MB.
MongoDB的Filesystem cache默认会使用完所有的除Internal cache和其它进程未使用的内存。其策略取决于操作系统,尽可能的将使用过的数据缓存到Filesystem cache中。当内存不足时,使用LRU(最近最少使用算法)淘汰数据。Filesystem cache的管理其实质时操作系统的缓存管理。
By default, WiredTiger uses Snappy block compression for all collections and prefix compression for all indexes. Compression defaults are configurable at a global level and can also be set on a per-collection and per-index basis during collection and index creation.
Different representations are used for data in the WiredTiger internal cache versus the on-disk format:
Via the filesystem cache, MongoDB automatically uses all free memory that is not used by the WiredTiger cache or by other processes.
设置Internal cache的大小,与 MongoDB 的工作集紧密相关。
什么是 working set
Working set represents the total body of data that the application uses in the course of normal operation. Often this is a subset of the total data size, but the specific size of the working set depends on actual moment-to-moment use of the database.
If you run a query that requires MongoDB to scan every document in a collection, the working set will expand to include every document. Depending on physical memory size.
For best performance, the majority of your active set should fit in RAM.
working set是DB所有数据的一个子集,它的大小取决于操作数据库的行为和时间。例如,一次查询的的所有数据。 为了最好的性能,大多数的常用的working set应该保留在内存中。
设置Internal cache应考虑多方面的因素。首先是MongoDB本身所在的操作系统环境,其操作环境中,是否有其它应用程序占用内存资源,占有后,服务器剩余的的空间大小如何,会超过设置的Internal cache的大小吗?然后是计算working set,使MongoDB能发挥其最好的性能。
一般情况下,mongo所在的服务器不适合安装过多的应用程序。设置Internal cache的大小也不宜超过mongo的默认设置( 50% of (RAM - 1 GB) )。
如果排除了操作系统中其它程序的的影响,我认为mongo的默认设置( 50% of (RAM - 1 GB) )是非常合理的,不用在配置上做任何修改。如果一定要指定Internal cache以特定值,应考虑上述两种因素,使MongoDB在稳定的,高性能的状态下运行。
《Mongo Storage》