大家好日子!
问题:( Sharded MongoDB)mapReduce操作返回:
MR后处理失败:{result:{db:“repu”,collection:“stat”},chunkSizes:[{_ id:MinKey},5759761],错误:“异常:insertDocument ::由:: 11000引起E11000重复键错误索引:repu.stat。$ id dup key:{:“B1000028748293459927”}“,代码:11000,ok:0.0}
在Mongod日志中找到多个类似的警告(所有返回MR命令之前):
警告:ClientCursor :: staticYield无法解锁b / c的递归锁ns:top:{opid:141587,active:true,secs_running:1,op:“query”,ns:“repu.stat”, query:{$ msg:“query not recording(too large)”},client:“92.36.25.144:57829”,desc:“conn2”,connectionId:2,locks:{^:“W”},waitingForLock:false ,msg:“m / r:减少后处理M / R减少后处理进度:14779/22241 66%”,进度:{完成:14779,总计:22241},numYields:0,lockStats:{timeLockedMicros:{r: 0,w:158575},timeAcquiringMicros:{r:0,w:30179}}}
在没有分片的单个Mongod(2.6.1)中运行时,完全相同的任务是成功的。但是在3-shard集群上运行时失败(所有分片都在一台Windows 7计算机上运行)。
问题的背景:
1)我们正在不断重复通过mapReduce()从(外部填充的)“inpu”集合中逐步更新“stat”集合的作业。工作类似于http://docs.mongodb.org/manual/tutorial/perform-incremental-map-reduce/
2)应用于“inpu”集合的map()会发出一些“uid”键(自定义几乎随机的20个字符串,如“B1000028748293459927”)。这些应该减少并成为目标“stat”集合的“_id”键。
3)“inpu”集合以“uid”键分片(正确编入索引,并以“uid”作为分片键启用)
4)目标“stat”集合由“_id”自动索引,并自动以“_id”分片为分片键。由于mapReduce调用,启用此分片 {out:{reduce:“stat”,db:“repu”,分片:true}}
5)重复的工作不断运行步骤 - 从“inpu”中删除()数据(但保留索引) - 使用批量插入新数据部分填充“inpu”(可能包含一些已经看过的“uid”,以及一些新的) - 在“inpu”上运行mapReduce(),输出减少到“stat” - (最终报告“stat”中的内容) - 并再次从remove()迭代。
6)从Java应用程序(Java Driver:mongo-java-driver-2.12.0.jar)启动作业, 调用mapReduce的Java代码片段是:
BasicDBObject cmdo =
new BasicDBObject( "mapReduce", "inpu" )
.append("map", mapFcn)
.append("reduce", reduceFcn)
.append("out",
new BasicDBObject("reduce", "stat")
.append("db", "repu")
.append("sharded", true)
)
.append("scope", scope);
// Setup optional finalize function
if (null != finalizeFcn) {
cmdo.append("finalize", finalizeFcn);
}
// Execute MapReduce
Logger.getGlobal().info("MapReduce sharded (inpu to stat) started");
CommandResult out = db.command( cmdo );
Logger.getGlobal().info("MapReduce done: [OK = " + out.ok() + "] "
+ collinpu.getCount() + " to "
+ collstat.getCount() + " records");
Logger.getGlobal().info("Error message: " + out.getErrorMessage() );
Logger.getGlobal().info("Results: " + out.toString() );
所有* .js函数(mapFcn,reduceFcn和未使用的finalizeFcn)都是从文本文件中读取的纯String。
7)mapReduce返回“half” - 人口“stat”集合,几乎有50%的“_id”缺失, 与初始“uid”组合比较时。这个“stat”集合是无用的,我们不能逻辑地“回滚”不成功的mapReduce() - s(由于我们的reduce()算法精心设计的“压缩”性质)。
8)由于复杂的reduce()算法,我们无法使用聚合框架。
9)当仅使用一个独立的Mongod服务器时,相同的任务成功运行。在这种情况下,没有任何分片,所有js脚本和mapReduce()运行良好。
10)并非处理循环中的所有mapReduce()作业都失败。其中一些运行成功(即使在之前的一些失败之后)。整个问题是“半解决”,这比根本没有解决更糟糕。
我们的痛苦: 那么,我们做错了什么,以及为什么输出集合中的某些“_id”试图保持“重复”(而不是像非分片情况那样正确缩小)?
此致 Serge Terekhov