有可能提高Mongoexport的速度吗?

Ana*_*eev 5 performance mongodb

我有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
Run Code Online (Sandbox Code Playgroud)

实际上,它是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
Run Code Online (Sandbox Code Playgroud)

我试图在这样的单独进程中使用--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
Run Code Online (Sandbox Code Playgroud)

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

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

我在场所表上没有索引。

我的存储配置:

journal.enabled: false
wiredTiger.collectionConfig.blockCompressor: zlib
Run Code Online (Sandbox Code Playgroud)

收集统计信息:

'ns': 'maps.places',
'size': 2360965435671,
'count': 130084054,
'avgObjSize': 18149,
'storageSize': 585095348224.0
Run Code Online (Sandbox Code Playgroud)

我的服务器规格:

Windows Server 2012 R2 x64
10Gb RAM 4TB HDD 6 cores Xeon 2.2Ghz
Run Code Online (Sandbox Code Playgroud)

我已经进行了一项测试,使用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
Run Code Online (Sandbox Code Playgroud)

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

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

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

kev*_*adi 5

限制出口业绩的因素有很多。

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

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

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

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

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

为此,请_id根据mongoexport您计划运行的进程数划分对应的命名空间。

例如,如果我有 200,000 个文档,从_id:0to开始_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 &
Run Code Online (Sandbox Code Playgroud)

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

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

使用1个过程:

real    0m32.720s
user    0m33.900s
sys 0m0.540s
Run Code Online (Sandbox Code Playgroud)

2个过程:

real    0m16.528s
user    0m17.068s
sys 0m0.300s
Run Code Online (Sandbox Code Playgroud)

4道工序:

real    0m8.441s
user    0m8.644s
sys 0m0.140s
Run Code Online (Sandbox Code Playgroud)

8道工序:

real    0m5.069s
user    0m4.520s
sys 0m0.364s
Run Code Online (Sandbox Code Playgroud)

根据可用资源,mongoexport并行运行 8 个进程似乎可以将进程加速约 6 倍。这是在一台 8 核的机器上测试的。

注意:halfer 的答案在想法上是相似的,尽管这个答案基本上是试图看看mongoexport并行调用是否有任何好处。

  • @halfer 很好,固定。顺便说一句,字符串在 MongoDB 中是可比的。 (2认同)

Ima*_*ica 1

我不使用 Mongo,但可以使用一个常见的技巧:制作一个简单的应用程序,可以有效地按顺序查询所有数据,过滤数据并以您想要的格式保存。

如果您需要以复杂的格式保存并且没有库可以使用它(我真的很怀疑),那么读取全部、过滤、将其放回到临时集合中、完全导出该集合、删除可能仍然有效。临时收集。