位置: 编程技术 - 正文

MongoDB使用小结:一些不常见的经验分享(mongodb项目使用说明)

编辑:rootadmin

推荐整理分享MongoDB使用小结:一些不常见的经验分享(mongodb项目使用说明),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:mongodb基本使用,mongodb基本操作,mongodb使用方法,mongodb基本操作,mongodb 实际 应用,mongodb使用场景 简书,mongodb使用方法,mongodb使用场景 简书,内容如对您有帮助,希望把文章链接给更多的朋友!

本文完成时MongoDB的最新版本为MongoDB 2.6

1、count统计结果错误

这是由于分布式集群正在迁移数据,它导致count结果值错误,需要使用aggregate pipeline来得到正确统计结果,例如:

db.collection.aggregate([{$group: {_id: null, count: {$sum: 1}}}])

引用:“On a sharded cluster, count can result in an inaccurate count if orphaned documents exist or if a chunk migration is in progress.”

参考:

2、从shell中更新/写入到文档的数字,会变为float类型

引用:“shell中的数字都被MongoDB当作是双精度数。这意味着如果你从数据库中获得的是一个位整数,修改文档后,将文档存回数据库的时候,这个整数也就被换成了浮点数,即便保持这个整数原封不动也会这样的。”

参考:《MongoDB权威指南》第一版

3、restore数据到新DB时,不要去先建索引

把bson数据文件restore到另一个DB时,需要注意:不能先创建索引再restore数据,否则性能极差,mongorestore工具默认会在restore完数据时,根据dump出来的index信息创建索引,无须自己创建,如果是要更换索引,也应该在数据入库完之后再创建。

4、DB中的namespace数量太多导致无法创建新的collection

错误提示:error: hashtable namespace index max chain reached:,如何解决呢?这是DB中的collection个数太多导致,在实践中以每个collection 8KB计算(跟官方文档里说的不同,可能跟index有关系),MB可以支持个collection。db.system.namespaces.count() 命令可以统计当前DB内的collection数目,DB可支持collection数量是由于nssize参数指定的,它指定了dbname.ns磁盘文件的大小,也就指定了DB可支持的最大collection数目,ns为namespace缩写。默认nssize为MB。如果重启MongoD并修改了nssize参数,这新nssize只会对新加入的DB生效,对以前已经存在的DB不生效,如果你想对已经存在的DB采用新的nssize,必须在加大nssize重启之后新建DB,然后把旧DB的collection 复制到新DB中。namespace限制相关文档: failed to engage TO-shard in the data transfer: can't accept new chunks because there are still 1 deletes from previous migration“。意思是说,当前正要去接受新chunk 的shard正在删除上一次数据迁移出的数据,不能接受新Chunk,于是本次迁移失败。这种log里显示的是warning,但有时候会发现shard的删除持续了十几天都没完成,查看日志,可以发现同一个chunk的删除在不断重复执行,重启所有无法接受新chunk的shard可以解决这个问题。参考: "_id" : "balancer", "activeWindow" : { "start" : ":", "stop" : ":" }, "stopped" : false, "_waitForDelete" : true },这样就不会因delete堆积而导致后续migrate失败,当然,需要考虑到这里的阻塞是否会影响到程序正常运转,在实践中慎重采用使用waitForDelete,因为发现加上它之后迁移性能非常差,可能出现卡住十几个小时的情况,外界拿住了被迁移chunk的游标句柄,这时候删除不能执行,阻塞了后续其它迁移操作。游标被打开而导致被迁移数据无法及时删除时的日志:--T::.+ [RangeDeleter] rangeDeleter waiting for open cursors in: cswuyg_test.cswuyg_test, min: { _id: - }, max: { _id: - }, elapsedSecs: , cursors: [ ]这可能会卡住几十小时,甚至一直卡住,影响后续的moveChunk操作,导致数据不均衡。解决方法还是:重启。

6、bson size不能超过MB的限制

单个文档的BSON size不能超过MB。find查询有时会遇到MB的限制,譬如使用$in 查询的时候,in中的数组元素不能太多。对一些特殊的数据源做MapReduce,MapReduce中间会将数据组合为“KEY:[VALUE1、VALUE2]”这样的格式,当value特别多的时候,也可能会遇上MB的限制。 限制无处不在,需要注意,”The issue is that the MB document limit applies to everything - documents you store, documents MapReduce tries to generate, documents aggregation tries to return, etc.

7、批量插入

批量插入可以减少数据往服务器的提交次数,提高性能,一般批量提交的BSON size不超过MB,如果超过了,驱动程序自动修改为往mongos的多次提交。

8、安全写入介绍及其沿革

关键字:acknowledge、write concern。

在年月之前,MongoDB驱动、shell客户端默认是不安全写入,也就是fire-and-forget,动作发出之后,不关心是否真的写入成功,如果这时候出现了_id重复、非UTF8字符等异常,客户端不会知道。在年月之后,默认为安全写入,安全级别相当于参数w=1,客户端可以知道写入操作是否成功。如果代码使用Mongo或者Collection来连接数据库,则说明它是默认不安全写入的legacy代码,安全写入已经把连接数据库修改为MongoClient接口。安全写入可以分为三个级别,第一级是默认的安全写入,确认数据写入到内存中就返回(w=N属于这一级);第二级是Journal save,数据在写入到DB磁盘文件之前,MongoDB会先把操作写入到Journal文件,这一级指的是确认写入了Journal文件就返回;第三级是fysnc,所有数据刷写到到DB磁盘文件才返回。一般第一级就足够了,第二级是为了保证在机器异常断电的情况下也不会丢失数据。安全写入要付出性能的代码:不安全写入的性能大概是默认安全写入的3倍。使用fync参数则性能更差,一般不使用。如果是副本集(replica set),其w=N参数,N表示安全写入到多少个副本集才返回。参考: {"age": 1, "username": 1}组合索引B: {"username": 1, "age": 1}全量查询: db.user.find({"age": {"$gte": , "$lte": }}).sort({"username" :1}),使用索引A的性能优于索引B。限量查询: db.user.find({"age": {"$gte": , "$lte": }}).sort({"username": 1}).limit(),使用索引B的性能优于索引A。这两个查询在使用索引A的时候,是先根据age索引找到符合age的数据,然后再对这些结果做排序。使用索引B的时候,是遍历name,对应的数据判断age,然后得到的结果是name有序的。优先使用sort key索引,在大多数应用上执行得很好。参考:《MongoDB——The Definitive Guide 2nd Edition》page

、查询时索引位置的无顺序性

做find的时候,并不要求索引一定要在前面,譬如:db.test集合中对R有索引db.test.find({R:"AA", "H": "BB"}).limit().explain()db.test.find({"H":"BB", "R" : "AA"}).limit().explain()这两个查找性能一样,它都会使用R索引。

、使用组合索引做shard key可以大幅度提高集群性能

“固定值+增量值” 两字段做组合索引可以有效的实现分布式集群中的分散多热点写入、读取。以下为读书笔记:在单个MongoDB实例上,最高效的写入是顺序写入,而MongoDB集群则要求写入能随机,以便平均分散到多个MongoDB实例。所以最高效的写入是有多个局部热点:在多个MongoDB实例之间是分散写入,在实例内部是顺序写入。 要实现这一点,我们采用组合索引。例如:shardkey的第一部分是很粗糙的,可选集很少的字段,索引的第二部分是递增字段,当数据增加到一定程度时,会出现很多第一部分相同第二部分不同的chunk,数据只会在最后一个chunk里写入数据,当第一部分不同的chunk分散在多个shard上,就实现了多热点的写入。如果在一个shard上,不止一个chunk可以写入数据,那也就是说不止一个热点,当热点非常多的时候,也就等同于无热点的随机写入。当一个chunk分裂之后,只能有一个成为热点,另一个不能再被写入,否则就会产生两个热点,不再写入的chunk也就是死掉了,后续只会对它有读操作。

最典型的应用是具有日期属性的日志处理,shard key选择“日期+用户ID”组合,保证了数据写入时的局部热点(一个shard上只有少数几个chunk被写入,避免随机IO)和全局分散(所有的shard上都有写入数据,充分利用磁盘IO)。我在实践中除了书中讲到的组合键方式外,还加上了预分片策略,避免了早期数据增长过程中的分片和数据迁移。另外还尽可能的制造能利用局部性原理的数据写入,例如在数据写入之前先对数据排序,有大约%左右的update性能提升。

预分片是这样子做的:根据组合shardkey信息先分裂好chunk,把这些空chunk移动到各个shard上,避免了后续自动分裂引起的数据迁移。

good case:

环境:一台机器、7分片、MongoDB2.6版本、shard key选择“日期+用户ID组合”,

数据:写入使用批量插入,对亿条日志级分片集群的写入,写入W条日志只需要分钟,每条日志约0.K。

bad case:

环境:3台机器、分片、MongoDB2.6版本、shard key选择 _id的hashid

数据:写入采用批量插入,对3亿条日志级分片集群的写入,写入W条日志耗时分钟,每条日志约0.K。

从对比可以看到,在数据量比较大的情况下选择组合索引做shard key性能明显优于选择hashid。

我在实际应用中还遇到选择hashid的更极端情况:对3条机器&分片&3亿条日志集群每天写入W条日志,耗时分钟,每条日志约4K。每次写入数据时,所有分片磁盘IO使用率都达到%。

MongoDB使用小结:一些不常见的经验分享(mongodb项目使用说明)

附创建组合索引和使用组合索引做shard key 的 mongo shell代码:

xx> db.cswuyg.ensureIndex({'code':1, 'insert_time':1})

xx> use admin

admin> db.runCommand({"enablesharding":"xx"})

admin> db.runCommand({"shardcollection":"xx.cswuyg","key":{'code':1, 'insert_time':1}})

参考:《MongoDB——The Definitive Guide 2nd Edition》 page

、怎么建索引更能提高查询性能?

在查询时,索引是否高效,要注意它的cardinality(cardinality越高表示该键可选择的值越多),在组合索引中,让cardinality高的放在前面。注意这里跟分布式环境选择shard key的不同。以下为读书笔记:index cardinality(索引散列程度),表示的是一个索引所对应到的值的多少,散列程度越低,则一个索引对应的值越多,索引效果越差:在使用索引时,高散列程度的索引可以更多的排除不符合条件的文档,让后续的比较在一个更小的集合中执行,这更高效。所以一般选择高散列程度的键做索引,或者在组合索引中,把高散列程度的键放在前面。参考:《MongoDB——The Definitive Guide 2nd Edition》 page

、非原地update,性能会很差

update文档时,如果新文档的空间占用大于旧文档加上它周围padding的空间,那么就会放弃原来的位置,把数据拷贝到新空间。参考:《MongoDB——The Definitive Guide 2nd Edition》 page

、无法在索引建立之后再去增加索引的过期时间

如果索引建立指定了过期时间,后续要update过期时间可以这样子:db.runCommand({"collMod":"a", index:{keyPattern:{"_":-1}, expireAfterSeconds: }})。

注意,通过collMod能修改过期时间的前提是:这个索引有过期时间,如果这个索引之前没有设置过期时间,那么无法update,只能删了索引,重建索引并指定过期时间。参考: Definitive Guide 2nd Edition》 page

、paddingFactor是什么?

它是存储空间冗余系数,1.0表示没有冗余,1.5表示%的冗余空间,有了冗余空间,可以让后续引发size增加的操作更快(不会导致重新分配磁盘空间和文档迁移),一般是在1到4之间。可以通过db.collection.stats()看到collection的该值“paddingFactor”。该值是MongoDB自己处理的,使用者无法设置paddingFactor。我们可以在compact的时候对已经有的文档指定该值,但这个paddingFactor值不影响后续新插入的文档。repairDatabase跟compact类似,也能移除冗余减少存储空间,但冗余空间少了会导致后续增加文档size的update操作变慢。虽然我们无法设置paddingFactor,但是可以使用usePowerOf2Sizes保证分配的空间是2的倍数,这样也可以起到作用(MongoDB2.6版本起默认启用usePowerOf2Size)。或者手动实现padding:在插入文档的时候先用默认字符占用一块空间,等到真实数据写入时,再unset掉它。

参考: pipeline 指定运算完成输出文档跟MapReduce相比有不足

(基于MongoDB2.6版本)MapReduce可以指定输出到特定的db.collection中,例如:out_put = bson.SON([("replace", "collection_name" ), ("db", "xx_db")])aggregate pipeline只能指定collection名字,也就意味着数据只能写入到本db,同时结果不能写入到capped collection、shard collection中。相比之下,aggregate pipeline限制是比较多的,如果我们需要把结果放到某个DB下,则需要再做一次迁移:db.runCommand({renameCollection:"sourcedb.mycol",to:"targetdb.mycol"})但是!!上面的这条命令要求在admin下执行,且只能迁移往同shard下的DB,且被迁移的collection不能是shard的。附错误码信息: "Don't recognize source or target DB", confFrom && confTo);uassert(, "You can't rename a sharded collection", !confFrom->isSharded(fullnsFrom));uassert(, "You can't rename to a sharded collection", !confTo->isSharded(fullnsTo));uassert(, "Source and destination collections must be on same shard", shardFrom == shardTo);参考: $ mongo --port > use admin> db.shutdownServer()2)1方式的简化:eg:mongo admin --port --eval "db.shutdownServer()"3)使用MongoD命令行关闭,需要指定db路径:mongod --dbpath ./data/db --shutdown

、集群的shard key慎重采用hash

如果你的日志是有日期属性的,那么shard key不要使用hash,否则删除过期日志时无法成块删除;在更新日志的时候,也不能利用局部性原理,查找、更新、插入数据都会因此而变慢。一般来说,hash id应付小数据量时压力不大,但在数据量较大(热数据大于可用内存容量)时,CRUD性能极差,且会放大碎片对性能的影响:数据非常分散,当有过期日志被删除后,这些删除后的空间成为碎片,可能会因为磁盘预读策略被加载到内存中。另外,采用hash shard key还会浪费掉一个索引,浪费不少空间。

、副本数也不用太多

如果你的副本数量超过了个(MongoDB3.0.0超过了个),那么就要选择使用 master-slave ,但这样会失去故障自恢复功能,主节点故障时,需要手动去切换到无故障节点。

、mongos的config server配置信息中不要使用localhost、.0.0.1

启动mongos时,config server的配置信息不得使用localhost、.0.0.1,否则添加其它机器的shard时,会出现错误提示:"can't use localhost as a shard since all shards need to communicate. either use all shards and configdbs in localhost or all in actual IPs host: xxxxx isLocalHost"

以新的config server启动mongos,也需要重启config server,否则会有错误提示:“could not verify config servers were active and reachable before write”

如果改完后面又出现 “mongos specified a different config database string” 错误,那么还需要重启mongod,

修改了config server 几乎是要全部实例重启。另外,在配置replica set时也不得使用localhost、.0.0.1。参考: key的选择跟update性能紧密关联

分布式MongoDB,shard key的选择跟update性能,甚至是update可用性有很大关系,需要注意。1、在对文档个别字段update时,如果query部分没有带上shard key,性能会很差,因为mongos需要把这条update语句派发给所有的shard 实例。2、当update 的upsert参数为true时,query部分必须带上 shard key,否则语句执行出错,例子:mongos> db.test.update({"_id":".AAABCDDAD5"}, {"$set":{"P": "aaa"}, "$setOnInsert":{"TEST":"a"}}, true)WriteResult({"nMatched" : 0,"nUpserted" : 0,"nModified" : 0,"writeError" : {"code" : ,"errmsg" : "upsert { q: { _id: ".AAABCDDAD5" }, u: { $set: { P: "aaa" }, $setOnInsert: { TEST: "a" } }, multi: false, upsert: true } does not contain shard key for pattern { _: 1.0, B: 1.0 }"}})这是因为如果没有shard key,mongos既不能在所有shard实例上执行这条语句(可能会导致每个shard都插入数据),也无法选择在某个shard上执行这条语句,于是出错了。另外,需要特别注意,如果使用pymongo引擎,它不会告诉你出错了,只是函数调用陷入不返回,在shell下执行才能看到错误信息。

附:以下英文部分来自: actually not clear to me that this is something we can support - problem is this:> db.coll.update({ _id : 1 }, { }, true);> db.coll.find(){ "_id" : ObjectId("a2bc4dcfa") }Upserts generate new _ids in response to this operation, and therefore we can't actually target this correctly in a sharded environment. The shard on which we need to perform the query may not be the shard on which the new _id is placed.意思是说,upsert产生了新的_id,_id就是shard key,但是如果query里没有shard key,它们不知道要到哪个shard上执行这个命令,upsert产生的shard key可能并不是执行这条命令的shard的。另外,如果_id不是shard key我们的例子也是不能成功的,因为没有shard key,这条upsert要在哪个shard上执行呢?不能像普通update那样给所有的shard去做,否则可能导致插入多条。参考: --dbpath /path/to/corrupt/data --repair --repairpath /media/external-hd/data/db,实例的数据会拷贝到/media/external-hd/data/db上做处理。

参考:《MongoDB——The Definitive Guide 2nd Edition》page

、索引字段的长度不能大于字节

索引字段的长度不能大于字节,否则shell下会有插入错误提示:"errmsg" : "insertDocument :: caused by :: Btree::insert: key too large to index”。使用pymongo的“continue_on_error”参数,不会发出错误提示,要注意。参考: [migrateThread] warning: failed to create index before migrating data. idx: { v: 1, key: { _: -1 }, name: "__-1", ns: "cswuyg_test.cswuyg_test", expireAfterSeconds: } error: IndexOptionsConflict Index with name: __-1 already exists with different options检查发生moveChunk的两个shard,并没有发现不一致,怀疑存在缓存,重启所有shard解决。

、config DB无法写入

因config DB无法修改,只可读,导致drop、enablesharding失败:config server 相关日志:--T::.+ [replmaster] local.oplog.$main Assertion failure isOk() src/mongo/db/storage/extent.h mongos 相关日志: [LockPinger] warning: pinging failed for distributed lock pinger 'xxx:/xxx:::'. : : caused by :: isOk()这是同事遇到的问题,不确定是什么操作引起的。重启、configdb做repair均无法解决。最后通过dump、restore解决:(1)把旧configdb dump出来;(2)restore到新的configure server;(3)mongos采用新的configure server;(4)重启全部mongod。

、sort()方法的size限制

当我对一个没有建索引的字段做find,然后做sort的时候,可能触发sort的size的MB限制,例如:

有两种解决方法:解决方法一:对需要排序的字段建索引 db.stotal.ensureIndex({'type': -1})解决方法二:修改默认配置,把sort时可以用的内存设置大点:cswuyg> db.adminCommand({setParameter:1, internalQueryExecMaxBlockingSortBytes:})参考:

MongoDB使用小结 一些常用操作分享 MongoDB的使用之前也分享过一篇,稍微高阶点:见这里:《MongoDB使用小结》1、shell登陆和显示假设在本机上有一个端口为的MongoDB服务,假设已经把mon

深究从MongoDB的ObjectId中获取时间信息 MongoDB默认使用_id字段作为主键,类型为ObjectId。ObjectId的生成有一定的规则,详情可以查看这篇文章-MongoDB深究之ObjectId。如果你在写入数据库的时候忘

Windows下mongodb安装与配置三步走 前言最近在重新学习node,所以和同事一起搞了个模仿新浪微博的项目,项目刚开始,所以其他的东西就暂时先不提。这里介绍下mongodb的安装。直接搜索

标签: mongodb项目使用说明

本文链接地址:https://www.jiuchutong.com/biancheng/312616.html 转载请保留说明!

上一篇:mongodb 常见问题处理方法收集(mongodb常见问题)

下一篇:MongoDB使用小结 一些常用操作分享(mongodb使用场景总结)

  • 动态市盈率与静态市盈率区别百度百科
  • 个人所得税本期收入是扣完保险吗
  • 新办企业申请一般纳税人的资料
  • t3怎么查资产负债表
  • 怎么恢复自然人个人信息
  • 材料采购合同需要注意什么
  • 当月有进项无销项月末怎么处理
  • 贴现率与现值系数的关系
  • 应收账款项目分析思维导图
  • 临时工工资能否用公户支付
  • 车辆购置税发票电子版怎么查
  • 标准的现金流量表格式
  • app 开发公司的账务处理
  • 建筑安装工程承包合同
  • 新成立的公司银行存款如何入账
  • 物业费增值税收入的确认最新政策
  • 银行已扣社保会计分录怎么做
  • 咨询服务费记到什么科目
  • 个税返还交所得税吗
  • 红字发票怎么做帐
  • 增值税专用发票验票
  • 如何查找使用过的手机号
  • 金融保险业的行业规范及标准
  • 防伪税控减免税款的会计分录
  • 核定征收和定期定额的区别
  • 增长率应该要如何计算呢?
  • 工程费用包括哪几类
  • 收取国外技术服务费如何在外管申报个税
  • 上年度职工工资总额
  • 汇算清缴后需要退税如何操作?
  • 五月份开的发票但是七月冲红了七月增值税怎么报
  • 谷歌浏览器adobe flash player已不再支持
  • 积极的财政政策有哪些
  • 微软输入法打不出汉字
  • 营改增后企业要交哪些税
  • 税收滞纳金可以抵税吗
  • 自然人税收管理系统扣缴客户端怎么操作
  • 控制系统动力学
  • php怎么将数据库中的数据显示出来
  • gpt最大
  • 隔两个月发票如何作废
  • 维保措施及售后服务方案
  • 公司名下的车怎么交税
  • 验证码php代码
  • 织梦文章内容图片大全
  • python3.9怎么删除
  • 纳税人识别号和公司税号一样吗
  • 外地预缴个人所得税凭证怎么弄
  • 小企业会计准则没有以前年度损益调整科目
  • 做无票收入如何报税
  • 记账凭证背面贴原始凭证图片
  • 银行的结息怎么做会计分录
  • 在建工程的人工费会计分录
  • 股权部分转让如何计算
  • win8怎么卸载
  • windows 9
  • freebsd软件安装
  • 使用u盘安装macos
  • centos安装nf_conntrack
  • 如何用u盘安装win8操作系统
  • xp系统个性化
  • xp系统电脑开机密码忘记了
  • sentstrt.exe - sentstrt进程是什么文件 有什么用
  • Win10 Mobile RedStone预览版14283更新内容汇总
  • Linux中的stat命令使用简介
  • windows如何编辑内容
  • 同步数据和异步数据的区别
  • nodejs静态编译
  • css如何控制图片位置
  • node.js连接不上数据库
  • vue是如何实现双向绑定的
  • 各种常用的js函数有哪些
  • jquery 日期
  • 网络ping大包
  • unity提高渲染画质
  • jquery轮播图自动播放
  • 关闭计算机盖的功能
  • 社保所属期起和所属期止是什么意思区别
  • 购买的土地没有土地使用证
  • 个人所得税app可以更改电话号码吗
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设