Sea*_*ark 0 javascript mongodb node.js
我有一个写入查询,它会在一分钟左右的时间内从源读取数据。但我还有一个需要从该数据库读取的应用程序。我那一刻不需要新数据。
写入查询锁定数据库,防止(通常很快)读取查询运行。
这是 currentOP() 的结果;
{
"inprog" : [
{
"opid" : 547909,
"active" : true,
"secs_running" : 0,
"microsecs_running" : NumberLong(104962),
"op" : "insert",
"ns" : "nb.article_raw",
"insert" : {
"$msg" : "query not recording (too large)"
},
"client" : "<<IP>>:52548",
"desc" : "conn10993",
"threadId" : "0x7ef7ebfb2700",
"connectionId" : 10993,
"locks" : {
"^" : "w",
"^nb" : "W"
},
"waitingForLock" : false,
"numYields" : 0,
"lockStats" : {
"timeLockedMicros" : {
"r" : NumberLong(0),
"w" : NumberLong(581)
},
"timeAcquiringMicros" : {
"r" : NumberLong(0),
"w" : NumberLong(15467)
}
}
},
{
"opid" : 546673,
"active" : true,
"secs_running" : 48,
"microsecs_running" : NumberLong(48720118),
"op" : "query",
"ns" : "nb.article_raw",
"query" : {
"id" : {
"$nin" : [ ]
},
"hasCompleteImage" : {
"$exists" : true
},
"date" : {
"$gt" : ISODate("2015-07-10T00:54:35Z")
}
},
"client" : "100.36.81.202:60791",
"desc" : "conn10979",
"threadId" : "0x7f55de5ae700",
"connectionId" : 10979,
"locks" : {
"^nb" : "R"
},
"waitingForLock" : true,
"numYields" : 6611,
"lockStats" : {
"timeLockedMicros" : {
"r" : NumberLong(19244958),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : {
"r" : NumberLong(18701993),
"w" : NumberLong(0)
}
}
}
]
}
Run Code Online (Sandbox Code Playgroud)
有什么想法可以编写第一个查询以使其不锁定吗?写入代码通过 NodeJS Mongo 驱动一次写入一个循环的迭代collection.insertOne
插入代码循环
promises.push(new Promise(function(resolve) {
collection.insertOne(obj, {}, function(err) {
if(err) {
}
resolve();
});
z++;
}));
Run Code Online (Sandbox Code Playgroud)
它位于对象的 foreach 内部。
因此,您可以在这里做一些事情,但通常您会在应用程序和服务器发行版中遇到“体系结构”。这意味着有一些事情(或者也许是全部)需要考虑。
我将在这里介绍基础知识,而不涉及“购买更多 RAM”或“获取更大的实例”游戏,并在“扩展”之前真正专注于“扩展”方面。
一遍又一遍地调用.insertOne()项目列表并不是真正有效,并且根据列表的大小可能真的会“锁定”您的数据库。
无论您使用什么来实现实际分辨率,我认为您确实应该查看批量操作 APi。写入不是单独发送,而是“批量”发送。所以以最简单的形式:
var bulk = collection.inititalizeUnorderedBulkOp();
listOfThings.forEach(function(obj) {
bulk.insert(obj);
});
// But actually sends to server here
bulk.execute(function(err,response) {
});
Run Code Online (Sandbox Code Playgroud)
对于非常大的列表,您可能不希望所有这些都在内存中进行列表处理或“批量”处理,因此应该进行一些限制。
关键是,一次向服务器发送 1000 个插入优于 1000 个请求和 1000 个响应,后者的流量很大。此外,这还允许在“批量”操作仅获取锁的情况下进行更多控制。与您在服务器上反复“敲击”一个又一个请求相比,这里有更多的“收益”空间用于其他操作。
既然您说您可以接受不在“绝对最新”数据上的查询,那么拥有 ReplicaSet 架构(无论如何您“应该”在生产中拥有它)就可以让您将“读取”推迟到辅助数据库。
虽然辅助节点“遵循更新”,但它们并没有像接受所有初始写入的主节点那样“努力”。所以这允许有更多的空间。
这里有“热点”,基本上同时读取和写入操作超载。分片允许您考虑通过跨分片分配写入来分散“写入负载”,或者通过利用可能不会发生在与“读取”来源相同的“分片”上的“写入”来分散“读取负载”从那个时间点开始,或者通常在搜索中进行“分散收集”并均匀地命中多个碎片。
因此,最终您会遇到“集合级锁定”或“数据库级锁定”,具体取决于可用版本。一个明显的变化是升级到 MongoDB 3.x 并使用Wired Tiger具有“文档级锁定”的
如果无法做到这一点,那么至少要考虑锁定级别以及:
尝试写入与您正在阅读的集合不同的另一个集合,并且仅“定期”更新“阅读集合”
或者,在数据库容器级别执行完全相同的操作。
这里的所有内容都是同一主题的变体,即“减少开销”和“尽可能分散负载”。因此,我至少会首先实现批量插入,因为总能从中获得一些好处。
然后查看此处的其他选项(不一定按提供的顺序,而是分片之前的副本集)并尝试获取写入之间的“冲突”级别。
还要看看“索引”,如果你有很多索引,它会减慢写入速度。人们索引超出实际需要的内容是很常见的,所以也要注意这一点。
| 归档时间: |
|
| 查看次数: |
1992 次 |
| 最近记录: |