MongoDB 创建大量集合测试问题

本文涉及的产品
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,通用型 2核4GB
简介:

问题背景

对使用 wiredtiger 引擎的 mongod 进行如下测试,不断的『创建集合、创建索引,插入一条记录』,然后统计这3个动作的耗时。

var db = db.getSiblingDB("testdb");
for (var i = 0; i < 100000; i++) {
    var start = (new Date()).getTime();
    var collName = "test" + i;
    var doc = {name: "name" +i, seq: i};
    db.createCollection(collName);        // 创建集合
    db[collName].createIndex({name: 1});  // 创建索引
    db[collName].insert(doc);             // 插入一条记录
    var end = (new Date()).getTime();     // 统计耗时
    print("cost: " + (end - start));
}

随着集合数越来越多,测试过程中发现2个问题

  1. 偶尔会出现耗时很长的请求(1s、2s、3s..不断上升),统计了下频率,大约1分钟左右出现一次。
  2. 平均耗时不断增加,从最开始平均10ms 不到,一直到20ms、30ms、40ms...

测试问题1

因为耗时很长的请求频率大概1分钟一次,跟 wiredtiger 默认的60scheckpoint 很接近,怀疑问题跟 checkpoint 有关,从运行慢日志看,耗时长是因为 createIndex 的原因。

通过当时的 pstack 发现,创建索引的线程正在等锁,只有 checkpoint 线程在干活

Thread 4 (Thread 0x7f80c3c72700 (LWP 70891)):
#0  0x00007f80c2ddc054 in __lll_lock_wait () from /lib64/libpthread.so.0
#1  0x00007f80c2dd7388 in _L_lock_854 () from /lib64/libpthread.so.0
#2  0x00007f80c2dd7257 in pthread_mutex_lock () from /lib64/libpthread.so.0
#3  0x00000000019f3f95 in __wt_curfile_open ()
#4  0x0000000001a580a5 in __session_open_cursor_int ()
#5  0x0000000001a09e13 in __wt_curtable_open ()
#6  0x0000000001a57f29 in __session_open_cursor_int ()
#7  0x0000000001a584b9 in __session_open_cursor ()
#8  0x000000000108cfe9 in mongo::WiredTigerIndex::BulkBuilder::openBulkCursor(mongo::WiredTigerIndex*) ()
#9  0x000000000108841e in mongo::WiredTigerIndexStandard::getBulkBuilder(mongo::OperationContext*, bool) ()
#10 0x0000000000cb09e9 in mongo::IndexAccessMethod::commitBulk(mongo::OperationContext*, std::unique_ptr<mongo::IndexAccessMethod::BulkBuilder, std::default_delete<mongo::IndexAccessMethod::BulkBuilder> >, bool, bool, std::set<mongo::RecordId, std::less<mongo::RecordId>, std::allocator<mongo::RecordId> >*) ()
#11 0x0000000000b07410 in mongo::MultiIndexBlock::doneInserting(std::set<mongo::RecordId, std::less<mongo::RecordId>, std::allocator<mongo::RecordId> >*) ()
#12 0x0000000000b0797d in mongo::MultiIndexBlock::insertAllDocumentsInCollection(std::set<mongo::RecordId, std::less<mongo::RecordId>, std::allocator<mongo::RecordId> >*) ()


Thread 68 (Thread 0x7f80b9336700 (LWP 37085)):
#0  0x00000000019db9e0 in __config_next ()
#1  0x00000000019dc106 in __config_getraw.isra.0 ()
#2  0x00000000019dc5a6 in __wt_config_getones ()
#3  0x0000000001a2437d in __wt_meta_ckptlist_get ()
#4  0x0000000001a65218 in __checkpoint_worker.isra.10 ()
#5  0x0000000001a64888 in __checkpoint_apply ()
#6  0x0000000001a6657a in __txn_checkpoint ()
#7  0x0000000001a66e17 in __wt_txn_checkpoint ()
#8  0x0000000001a57854 in __session_checkpoint ()
#9  0x00000000019e4f8f in __ckpt_server ()
#10 0x00007f80c2dd5851 in start_thread () from /lib64/libpthread.so.0
#11 0x0000003403ee767d in clone () from /lib64/libc.so.6

为什么建索引会跟 checkpoint 有冲突?分析索引代码发现,前台建索引时,mongod 会使用 wiredtiger 的 bulk cursor,而openBulkCursor是要竞争 checkpoint 锁的(个人理解是避免在 bulk insert 过程中出现 checkpoint),所以 createIndex 会阻塞等待 checkpoint 完成。

// src/cursor/cur_file.c:__wt_curfile_open
 /* Bulk handles require exclusive access. */
    if (bulk)
        LF_SET(WT_BTREE_BULK | WT_DHANDLE_EXCLUSIVE);

    /* Get the handle and lock it while the cursor is using it. */
    if (WT_PREFIX_MATCH(uri, "file:")) {
        /*
         * If we are opening exclusive, get the handle while holding
         * the checkpoint lock.  This prevents a bulk cursor open
         * failing with EBUSY due to a database-wide checkpoint.
         */
        if (LF_ISSET(WT_DHANDLE_EXCLUSIVE))
            WT_WITH_CHECKPOINT_LOCK(session, ret,
                ret = __wt_session_get_btree_ckpt(
                session, uri, cfg, flags));

另外从目前的实现看,后台建索引时并不是 bulk cursor,而是使用普通的 cursor 逐条插入,故不会去竞争 checkpoint 的锁,上述测试代码在createIndex 时加上{background: true}选项时问题解决。

建议用户在建立索引时,尽量选择后台建索引的方式,可能性能上不如前台方式,但后台建索引对业务的影响是最小的(前台建索引还会获取 db 的写锁,导致 db 上的读写都被阻塞),最好的方式是 DDL 和 DML 分离,在业务代码中不要出现建索引、建集合的逻辑,预先创建好,业务只做CRUD 操作。

测试问题2

这个问题主要跟文件系统机制相关,testdb 下创建了数万个集合,对应到 wiredtiger 的实现,会出现一个目录下数万个文件的情况(集合的每个索引也要对应一个文件),而从ext4文件系统层面上,在目录里创建文件,先要遍历整个目录下所有的文件项,文件越多效率越低。

上述问题通常的解决方法是『将扁平化的目录层次化』,对应到 mongodb,就是将数万个集合分散到多个 DB 里,具体方法如下。

  1. 配置 storage.directoryPerDB 选项为 true
  2. 业务上将集合分散到多个 DB 里(如100个,平均每个目录下就只有几百个文件)

总结

MongoDB 使用 wiredtiger 引擎时,大量集合的场景(通常业务设计上是有问题的),可能会遇到很多未知的问题,毕竟这不属于常见的应用场景,官方在这方面的测试支持也会相对弱些,比如上述提到的2个问题,还有之前分享的一个集合太多无法同步的问题,建议大家使用 MongoDB 时,合理设计数据模型,避免踩不必要的坑。

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
2月前
|
网络协议 Shell Linux
【Shell 命令集合 网络通讯 】⭐⭐⭐Linux 测试与目标主机之间的网络连接ping 命令 使用指南
【Shell 命令集合 网络通讯 】⭐⭐⭐Linux 测试与目标主机之间的网络连接ping 命令 使用指南
44 1
|
5月前
|
存储 人工智能 C#
【Unity 3D】C#中数组、集合、栈、队列、哈希表、字典的讲解(附测试代码)
【Unity 3D】C#中数组、集合、栈、队列、哈希表、字典的讲解(附测试代码)
39 0
|
8天前
|
DataWorks NoSQL 关系型数据库
DataWorks操作报错合集之在使用 DataWorks 进行 MongoDB 同步时遇到了连通性测试失败,实例配置和 MongoDB 白名单配置均正确,且同 VPC 下 MySQL 可以成功连接并同步,但 MongoDB 却无法完成同样的操作如何解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
25 1
|
14天前
|
监控 NoSQL 测试技术
MongoDB性能最佳实践:如何制定更有效的基准测试?
感谢你与我们一起走过这段MongoDB性能最佳实践之旅,希望你能从中获取一些有用的信息
1591 2
|
5月前
|
存储 人工智能 测试技术
软件测试/人工智能|一文告诉你Python集合相关知识
软件测试/人工智能|一文告诉你Python集合相关知识
35 0
|
6月前
|
NoSQL MongoDB 数据库
04 MongoDB - 集合操作
04 MongoDB - 集合操作
23 0
|
9月前
|
NoSQL MongoDB 数据库
MongoDB常用的操作(服务器、数据库、集合)
MongoDB常用的操作(服务器、数据库、集合)
1985 0
|
10月前
|
NoSQL MongoDB Cloud Native
【mongo 系列】mongodb 学习十一,MongoDB 分片集群之分片集合
MongoDB 中 分片集群有专门推荐的模式,例如 分片集合
106 0
|
10月前
|
存储 NoSQL Java
docker-compose部署mongodb4.4.8副本集群 + 权限 + springBoot集成测试
docker-compose部署mongodb4.4.8副本集群 + 权限 + springBoot集成测试
420 0
|
10月前
|
NoSQL MongoDB 数据库
MongoDB 删除集合
MongoDB 删除集合
79 0

相关产品

  • 云数据库 MongoDB 版