我有1.3亿行MongoDB 3.6.2.0集合。它具有几个简单字段和2个带有嵌套JSON文档的字段。数据以压缩格式(zlib)存储。

我需要尽快将嵌入字段之一导出为JSON格式。但是,mongoexport永远占据一席之地。运行12小时后,它仅处理了5.5%的数据,这对我来说太慢了。

CPU不忙。 Mongoexport似乎是单线程的。

我正在使用的导出命令:

mongoexport -c places --fields API \
    --uri mongodb://user:pass@hostIP:hostPort/maps?authSource=admin \
    -o D:\APIRecords.json

实际上,它是getMore命令,在后台运行得太慢了:
2018-05-02T17:59:35.605-0700 I COMMAND  [conn289] command maps.places command: getMore { getMore: 14338659261, collection: "places", $db: "maps" } originatingCommand: { find: "places", filter: {}, sort: {}, projection: { _id: 1, API: 1 }, skip: 0, snapshot: true, $readPreference: { mode: "secondaryPreferred" }, $db: "maps" } planSummary: COLLSCAN cursorid:14338659261 keysExamined:0 docsExamined:5369 numYields:1337 nreturned:5369 reslen:16773797 locks:{ Global: { acquireCount: { r: 2676 } }, Database: { acquireCount: { r: 1338 } }, Collection: { acquireCount: { r: 1338 } } } protocol:op_query 22796ms

我试过在像这样的单独进程中使用--SKIP--LIMIT选项运行多个命令
mongoexport -c places --SKIP 10000000 --LIMIT 10000000 --fields API \
    --uri mongodb://user:pass@hostIP:hostPort/maps?authSource=admin \
    -o D:\APIRecords.json
mongoexport -c places --SKIP 20000000 --LIMIT 10000000 --fields API \
    --uri mongodb://user:pass@hostIP:hostPort/maps?authSource=admin \
    -o D:\APIRecords.json

等等。但是直到第一个非零SKIP的命令甚至启动,我还是无法完成等待!

我还尝试了--forceTableScan选项,该选项没有任何区别。

我在场所表上没有索引。

我的存储配置:
journal.enabled: false
wiredTiger.collectionConfig.blockCompressor: zlib

收集统计信息:
'ns': 'maps.places',
'size': 2360965435671,
'count': 130084054,
'avgObjSize': 18149,
'storageSize': 585095348224.0

我的服务器规范:
Windows Server 2012 R2 x64
10Gb RAM 4TB HDD 6 cores Xeon 2.2Ghz

我进行了一项测试,使用SSD时,其读取吞吐量与使用HDD时相同。

我的问题:

为什么阅读这么慢?还有其他人遇到过同样的问题吗?您能给我一些有关如何加快数据转储的提示吗?

更新

我将数据库移到了快速的NVME SSD驱动器上,我想现在可以更清楚地说明我对MongoDB读取性能的担忧。

为什么执行此命令,以查找没有特定字段的文档块:
2018-05-05T07:20:46.215+0000 I COMMAND  [conn704] command maps.places command: find { find: "places", filter: { HTML: { $exists: false }, API.url: { $exists: true } }, skip: 9990, limit: 1600, lsid: { id: UUID("ddb8b02c-6481-45b9-9f84-cbafa586dbbf") }, $readPreference: { mode: "secondaryPreferred" }, $db: "maps" } planSummary: COLLSCAN cursorid:15881327065 keysExamined:0 docsExamined:482851 numYields:10857 nreturned:101 reslen:322532 locks:{ Global: { acquireCount: { r: 21716 } }, Database: { acquireCount: { r: 10858 } }, Collection: { acquireCount: { r: 10858 } } } protocol:op_query 177040ms

仅在快速闪存驱动器上产生50Mb/sec的读取压力?显然,这是单线程随机(分散)读取的性能。而我刚刚证明该驱动器可以轻松实现1Gb/秒的读取/写入吞吐量。

就Mongo内部而言,按顺序读取BSON文件并提高20倍的扫描速度是否明智? (并且,由于我的块是zlib压缩的,并且服务器具有16个内核,因此更好地在一个或几个辅助线程中解码获取的块吗?)而不是在文档之间迭代BSON文档。

我也可以确认,即使当我没有指定任何查询过滤器,并且显然要迭代整个IREIRE集合时,也不会发生快速顺序读取BSON文件的情况。

最佳答案

有许多因素限制了导出绩效。

  • 与可用内存相比,数据大小相对较大:〜2 TB与〜5 GB的WiredTiger缓存(如果设置为默认值)。那是:
  • 整个WiredTiger缓存最多只能包含〜集合的0.22%,实际上,它的数量可能要少得多,因为缓存将包含来自其他集合和索引的数据。
  • 这意味着WiredTiger需要非常频繁地从磁盘获取数据,同时逐出缓存的当前内容。如果正在积极使用副本集,这将意味着从缓存中清除“脏”数据并将其持久保存到磁盘,这将需要一些时间。
  • 请注意,WiredTiger缓存中的文档未压缩。
  • 该集合包含大型文档,您只需要其中一部分。这意味着需要更多时间来处理文档。
  • 该集合使用zlib压缩,这意味着必须花费额外的时间来解压缩文档。
  • readPreference是secondaryPreferred,这意味着它将尝试从辅助目录读取。如果正在积极地写入副本集,则辅助节点上的oplog Apply操作将阻止读取器。这将进一步增加延迟。

  • 一种可能的改进是,如果您经常执行此操作,则在相关字段上创建索引并使用covered query导出它可以提高性能,因为该索引将小于完整文档。

    编辑:在这种情况下,并行运行mongoexport可能会有所帮助:

    除了提供的其他信息外,我进行了一项测试,似乎在某种程度上缓解了此问题。

    似乎并行运行mongoexport,其中处理集合的子集的每个mongoexport可能能够加快导出速度。

    为此,请划分与计划运行的_id进程数量相对应的mongoexport命名空间。

    例如,如果我有200,000个文档,则从_id:0_id:199,999并使用2个mongoexport进程:
    mongoexport -q '{"_id":{"$gte":0, "$lt":100000}}' -d test -c test > out1.json &
    mongoexport -q '{"_id":{"$gte":100000, "$lt":200000}}' -d test -c test > out2.json &
    

    在上面的示例中,两个mongoexport进程各自处理集合的一半。

    用1个流程,2个流程,4个流程和8个流程测试此工作流,我得出以下时序:

    使用1个过程:
    real    0m32.720s
    user    0m33.900s
    sys 0m0.540s
    

    2个过程:
    real    0m16.528s
    user    0m17.068s
    sys 0m0.300s
    

    4个过程:
    real    0m8.441s
    user    0m8.644s
    sys 0m0.140s
    

    8个过程:
    real    0m5.069s
    user    0m4.520s
    sys 0m0.364s
    

    根据可用资源的不同,并行运行8个mongoexport进程似乎可以使该进程的速度提高约6倍。这是在具有8核的计算机上测试的。

    注意:Halfer的答案在思想上是相似的,尽管该答案主要是尝试查看并行调用mongoexport是否有任何好处。

    关于mongodb - 有可能提高Mongoexport的速度吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50145668/

    10-09 17:43