mongo规范
如果是一些不经常变的字段,如客户的姓名,地址,部门等,则可以尽管进行冗余
对 1:N(一些)的关系使用全部内嵌
这个时候如果把所有员工信息直接内嵌到部门内肯定不是个好的选择,有可能会超出16MB的文档限制。这个时候可以采用引用ID的方式:(更新性能优)
> db.departments.findOne() { name : ‘Enterprise BG’, president: ‘Zhang San’, employees : [ // array of references to Employee colletion ObjectID(‘AAAA’), ObjectID(‘F17C’), ObjectID(‘D2AA’), // etc ] }
你只需要在update语句中指定需要更新的字段,而不是整个文档对象。
举例来说,加入我想把用户的名字从TJ改
建议的做法:
user = db.users.findOne({_id: 101});
// do certain things
db.users.update({_id:101}, {$set: {name: “Tang Jianfa”}});
与其自己写个后台脚本定期清理过期数据,你可以使用TTL索引来让MongoDB自动删除过期数据:
db.data.createIndex({create_time:1}, {expireAfterSeconds: 7243600})
SpringData MongoDB里面的MongoTemplate有个execute方
https://zhuanlan.zhihu.com/p/338286940
https://blog.csdn.net/yx0628/article/details/79052713
mongo填充因子
objectId
doc = db.clients.findOne({_id: ObjectId(“4cc45467c55f4d2d2a000002”)}) // set a new _id on the document doc._id = ObjectId(“4c8a331bda76c559ef000004”) // insert the document, using the new _id db.clients.insert(doc) // remove the document with the old _id db.clients.remove({_id: ObjectId(“4cc45467c55f4d2d2a000002”)})
???
l 查询多长时间可以返回结果(仅限于使用executionStats模式)
l 那个可选择的查询方案被否决了(仅限于allPlansExecution模式)
所以MongoDB采用了另外一种主键生成策略。每一个主键由4部分构成:
1.unix时间戳,精确到秒级别;
2.机器id;
3.进程id;
4.计数器;
ggg
https://blog.csdn.net/weixin_31132687/article/details/113087819
ggg
可能需要将 Sharding 改造为 复制集
https://blog.csdn.net/weixin_33726313/article/details/89534415
mongodb目前在业界的使用一般可分为两种架构:主从复制集和分片复制集集群。
Mongodb一共有三种集群搭建的方式:
Replica Set(副本集)、
Sharding(切片)
当 collection 所占空间过大时,我们需要增加一台新的机器,分片会自动
将 collection 的数据分发到新的机器上。
mongos就是一个路由服务器,它会根据管理员设置的”片键”
将数据分摊到自己管理的mongod集群,数据和片的对应关系以及相应的配置信息保存在”config服务器”上。
客户端只需要对 mongos 进行操作就行了,至于如何进行分片,不需要 客户端参与,由 mongos 和 config 来完成。
如果不分片的话,我们会直接连上mongod。
https://www.cnblogs.com/nulige/p/7613721.html
分布式索引
现在:index特别大也得page替换。
For the fastest processing, ensure that your indexes fit entirely in RAM so that the system can avoid reading the index from disk.The indexes and the working set must be able to fit in memory at the same time.
没有搞定:
可以index分到集群多台机器的内存,整体内存的角度看index
https://blog.csdn.net/ITgagaga/article/details/103565738
Queries against primaries through mongos may include a SHARDING_FILTER stage which filters result documents that are not owned by the current shard (for example, due to migrations in progress where documents need to transiently exist on both a donor and target shard).
复制集上的index都是一样的
1.禁用复制链,将chainingAllowed=false
2.关闭一个备份节点服务器
3.将这个服务器以单机模式启动
4.在单机模式下创键索引
5.索引创建完成之后,将服务器作为副本集成员重新启动
6.对副本集的每个备份节点重复2~5步
现在除了主节点其他的复制集成员都创建了索引,现在有两个方式:
1)在主节点是创建索引(在主节点创建索引期间,不可用,可以修改读选项,在备份节点读取数据)
主节点创建索引完成之后,由于备份节点已经有了同样的索引,实际上不会再创建索引
原文链接:https://blog.csdn.net/ITgagaga/article/details/103565738
For the fastest processing, ensure that your indexes fit entirely in RAM so that the system can avoid reading the index from disk.The indexes and the working set must be able to fit in memory at the same time.
GridFS是一种将大型文件存储在MongoDB的文件规范。 GridFS 规范提供了一种透明的机制,可以将一个大文件分割成为多个较小的文档。这将容许我们有效的保存大的文件对象,特别对于那些巨大的文件,比如视频。
用于在数据库里存储二进制大文件
可以统一用数据库处理数据,而无需借助外部的文件系统
可以利用MongoDB的复制或分片机制,故障恢复和可扩展性较好
避免使用文件系统的某些限制(例如linux在同一目录下的文件数限制)
避免文件碎片(MongoDB分配空间以2GB作为单位)
文件被分成若干块(chunk),每个块作为一个文档存储
有一个单独的文档存储分块的信息,以及文件的元数据
fs.chunks集合
fs.files集合
#何时分片
单个节点的磁盘不足
单个mongod不能满足写数据的性能要求
将大量数据放到内存中提高性能
https://blog.csdn.net/zq9017197/article/details/17588553
当你想访问大型文件的部分信息,却不想加载整个文件到内存时,您可以使用GridFS存储文件,并读取文件部分信息,而不需要加载整个文件到内存。
GridFS使用两个集合(collection)存储文件。一个集合是chunks, 用于存储文件内容的二进制数据;一个集合是files,用于存储文件的元数据。GridFS会将两个集合放在一个普通的buket中,并且这两个集合使用buket的名字作为前缀。在files集合中找到对应的文档,同时得到_id字段,再根据_id在chunks集合中查询所有files_id等于_id的文档。最后根据n字段顺序读取chunk的data字段数据,还原文件。
MongoDB 不会释放已经占用的硬盘空间。即使删除db中的集合 MongoDB也不会释放磁盘空间。同样,如果使用GridFS存储文件,从GridFS存储中删除无用的垃圾文件,MongoDB依然不会释放磁盘空间的。这会造成磁盘一直在消耗,而无法回收利用的问题。
如沟通,基于少波方案的测试结果,mongo已经优化告以段落:
1 基于我司每秒同时查询少的场景,不开分片
2 由于仅保存一年数据,三台mongo集群(A、B、C)设置为:A主、B和C为备
3 后续如果有瓶颈,通过可以分库提高查询效率(java代码需要改动)
4 dump不影响现网程序,每个周期通过dump -query基于查询条件实现增量备份。
换分片键:
使用time,尽管升序片键不被推荐,但是可以采用半人工干预:开始使用了addShardTag,然后addTagRange,给平衡器指定特定时间范围数据位于某个shard上面,不过似乎没有起作用,其实分析一下,在原来可以均衡的片键下都没有成功,就平衡策略的第二种情形也是无法平衡的。
所以开始利用movePrimary力求数据全部写到这个主分片中,以降低原来主分片中磁盘的压力。其使用方法:
db.runCommand({“movePrimary”:”test”,”to”:”shard_1”})
创建索引的方式采用的是前台创建形式。所谓前台创建索引,所有的集合都将被锁住,包括读写,直到所有的索引都被创建完毕,是整个db的锁,所以,在移动的过程中不能有任何其他的读写操作。索引创建过程默认是前台方式,我们顺便了解下后台创建方式。后台创建过程不会影响其他的操作,但是其代价是速度很慢。特别的如果索引的大小大于可用的RAM,那么创建的过程将会非常漫长。
https://blog.csdn.net/tang_jin2015/article/details/74941456
自增字段的作用:
如果使用非自增主键(如果身份证号或学号等)
由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置,此时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。
总结:如果InnoDB表的数据写入顺序能和B+树索引的叶子节点顺序一致的话,这时候存取效率是最高的,也就是下面这几种情况的存取效率最高:
a、使用自增列(INT/BIGINT类型)做主键,这时候写入顺序是自增的,和B+数叶子节点分裂顺序一致;
b、该表不指定自增列做主键,同时也没有可以被选为主键的唯一索引(上面的条件),这时候InnoDB会选择内置的ROWID作为主键,写入顺序和ROWID增长顺序一致;
c、如果一个InnoDB表又没有显示主键,又有可以被选择为主键的唯一索引,但该唯一索引可能不是递增关系时(例如字符串、UUID、多字段联合唯一索引的情况),该表的存取效率就会比较差。
https://segmentfault.com/q/1010000003856705
结合公司内部使用MongoDB为例,有时候出现以下情况:一些不适合MongoDB的业务场景,例如全文检索、8字段以上的随机组合查询、非前缀匹配模糊查询,这些场景本身不适合选用MongoDB,但是业务选型错误,造成使用过程中的瓶颈。
由于mongodb是一个很懒的数据库,除了存储数据基本上不做什么运算,所以一旦有一定程度(根本不用多大量)的运算,你一定能感受到它的袅袅婷婷(采用js进行脚本运算),官方推荐mongodb尽量设计成自取式(冗余避免计算)。
讨论这个问题的方案:当某个复制集的备机down掉时,现在实现是备down是直接监控拉起,主down机时,基于备的成为主节点后的信息反馈再拉起老的down的主机。
这个需要改造一下:改为发现出现问题挺等半小时再拉起进程(看看是否有可能规避当时down机环境),同时将oplog的大小适度增加大小,这样down的时间内oplog空间够用不会覆盖,就不存在修复oplog问题。@陈竹-T4(陈竹) 这个代码请成功提供给少波,后续加入到指导书。
如果自动拉起不了,大概率手动也无法拉起,一线出现拉起后,主备都一一再次挂掉,整个系统down掉,这种场景只能基于备份恢复和datax恢复。
现在就这只能基于备份恢复。将来出现来不起了的情况,我们再多收集日志找原因。上T的东东,就只能基于全量备份和data恢复少量天数,恢复系统
现在mongoDB方案,导入方案基于复制集导入,不开启分片,导入完成后,对应6个月的数据量,内存足够大(3个256G),三个基础大表可以通过索引,不加分片解决。
现在要解决的问题是
1 不自动trunk迁移,能基于规则写入db机器时,直接写到对应分片对应的trunk,而不是现在都写到主的机器上,主的机器再trunk迁移,老的方式导致增加复制量、同时可能和复制集复制抢锁。
2 解决分片键、索引、分表的平衡设置和优化,降低索引的开销,能支持更长时间比如一年的mongo数据量,同时基于复制集导入完成时,基于平衡的设计,分片、索引的时间和仅全量的索引时间保存差不多即可。
目标:索引变小,导入加快,查询加快。第一场景 1 trunk数量;索引大小(查一下大小);强行关闭时的时间(第一导入时间时间);再看索引大小;2 4个条件查询( A 5个字段imsi大范围、uptime大范围、region小范围、placeid大范围,deviceid大范围 B 单独imsi大范围 C 单独uptime大范围 D 单独imsi大范围和单独uptime大范围 E 单独imsi大范围和单独uptime大范围、placeid大范围 );第二场景先复制集、再导入,再建索引: trunk情况,导入的时间;现有的数据量建索引时间,导入时间加索引时间就是系统导入成功时间,看索引大小;5个查询的时间记录;
第二步中需要完全按照现在3.4.1的index设置加索引后,记录 totalsize磁盘存储大小,datasize实际数据大小(未压缩)后,建立索引的时间,再导出;
第三步已经确定uptime不要,改为uptime、deviceid索引,还需要确认
1 _id索引、id索引能否都不搞(少波查找一下)
2 shard key的设置?设置目标:trunk预先建立,trunk数量不能太多,数据写入时基于shard keykey直接写入对应的trunk(系统均衡器关闭),写入得比较均匀
确认后:1 导入到另外的imsirecord2表 2 导表时建立复制集1: b(主)、c(备)、d(仲裁),复制集2:d(主)、c(备)、b(仲裁 )
3 分片和分片键建好后导入(),导入后建索引,后查询。需要导入时间加index建立时间和第二步比较、索引大小比较、查询快慢比较
第三步的可能index大小和第二种方式差不多(numInitialChunks设置为缺省的trunk数,和第二步的值一样,显示设置,balance设置为disable),分片键是placid+uptime的hashed,这个步骤目的:看看预分片的效果(不移trunk的导入速度),第二看看index大小 mongo由于B-树,在非叶子节点有很多数据,导致占很多内存,所以hashed导致叶子数据乱放不聚集也问题不大。
第四步代码手动split出trunk,基于placeid和uptime(月天),第四步的目的看看由于数据汇集,查询速度是否加快(一次100次查询比较),估计index不会变,导入也不会变。预split完全基于范围,可以基于prefix (https://docs.mongodb.com/manual/tutorial/create-chunks-in-sharded-cluster/),或tag可以绑定到shard更适合(http://m.bubuko.com/infodetail-1788810.html),这样一天内的数据就可以在多个分片能多读
(mongo还不能灵活定义分片的hash函数或规则)
第5步 zlib压缩算法压缩比约为4.5-7.5倍(本次迁移采用zlib高压缩算法);checkpoint调整?比如的值如下:checkpoint=(wait=25,log_size=1GB) cacheSize调小到50G、evict线程尽早淘汰脏页page到磁盘,增加evict淘汰线程数加快脏数据淘汰,避免用户请求线程进行脏数据淘汰,config库的system.sessions表启用分片功能(https://my.oschina.net/u/4390731/blog/4929468);db.setProfilingLevel(1) (https://www.cnblogs.com/duanxz/p/3746122.html)
Capped Collections
所有查询优先考虑在从库上读取,写操作在主库上执行。避免主库混合读写压力过大,也减少主库上读写记录的锁冲突。
connection string中readPreference 设置成secondarypreferred,C++ 驱动版本升级为3.1.3 mongo-cxx-driver(驱动升级,读写分离才生效) 。
journal 日志的 commitIntervalMs 参数调整。
从默认的100ms调大到500ms。
通过 mlogfilter / mloginfo 工具分析业务高峰期间出现的TOP10 慢查询。
链接:https://www.jianshu.com/p/e6790361c5da
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
第6步 zone的ssd
https://mongoing.com/archives/78710 监控
profile和计划是看sql执行情况的工具
https://www.cnblogs.com/duanxz/p/3746122.html
结果
1 导入时,5个split大于3个zone,所以一个磁盘2个进程更快导入
2 3分片加复制集比复制集更慢:保持db文件打开;trunk对应的实体是什么?
分片增加了并行查询度,但是查询速度,需要和
在Mongodb中,其提供了类似关系型数据中cursor对象来遍历数据集合,同时mongodb并要根据不同的场景生成不同的游标对象(cursor),比如顺序遍历游标(basicCursor),反向游标(reverseCursor), B树索引游标(btreeCursor)等。
https://www.cnblogs.com/daizhj/archive/2011/04/15/mongodb_cursor_source_code.html
迭代索引
在mongo shell 中可以使用游标的 toArray() 方法迭代遍历游标结果,并将结果集放在一个数组中返回。
var myCursor = db.inventory.find( { type: 2 } );
var documentArray = myCursor.toArray();
var myDocument = documentArray[3];
默认情况下,服务器会自动关闭超过10分钟活跃的或客户端已耗尽的游标。想不使用这个默认行为在 mongo shell 中可以使用ursor.noCursorTimeout()方法:
测试:
自带
https://www.cnblogs.com/guochunyi/p/5898719.html
对于批量插入功能,其实是一次提交一批数据,但是相比一次一条插入性能并没有提高多少
???安全插入
对于安全插入功能,相对来说比较稳定,不会波动很大,我想可能是因为安全插入是确保数据直接持久化到磁盘的,而不是插入内存就完事。
???二列条件返回小数据的查询
???对于一列数据外加Sort和Skip的查询; 特殊加其它索引
但是在多条件下有的时候甚至会比单进程高一点,某些时候数据块位于两个Sharding,这样Mongos会并行在两个Sharding查询,然后在把数据进行合并汇总,由于查询返回的数据量小,网络不太可能成为瓶颈了,使得Sharding才有出头的机会。
那么服务启动的初始化阶段,虽然可以接受数据的查询和修改,但是此时性能很差,
在使用Sharding的时候,Mongodb时不时会对数据拆分搬迁,这个时候性能下降很厉害,
能手动切分数据库就手动切分或者手动做历史库,不要依赖这种自动化的Sharding,因为一开始数据就放到正确的位置比分隔再搬迁效率不知道高多少。
对于数据的插入,如果使用多线程并不会带来性能的提高,
https://www.cnblogs.com/lovecindywang/archive/2011/03/02/1969324.html
MongoDB对业务来说就是一个无限大的表(当前我司最大的表存储数千亿数据,查询性能无任何影响)。
此外,业务在早期的时候一般数据都比较少,可以只申请一个分片MongoDB集群。
关于balance:支持自动balance、手动balance、时间段任意配置balance.
MongoDB客户端访问路由策略由客户端自己指定,该功能通过Read Preference实现,支持primary 、primaryPreferred 、secondary 、secondaryPreferred 、nearest 五种客户端均衡访问策略。
关于分片策略:支持范围分片、hash分片,同时支持预分片。
关于片建类型:支持单自动片建、多字段片建
支持不同类型的Read Concern 、Write Concern读写相关配置
MongoDB在线程模型设计、并发控制、高性能存储引擎等方面做了很多细致化优化。
wiredtiger引擎性能更好,压缩比更高,锁粒度更小,具体如下:
① WiredTiger提供了低延迟和高吞吐量
② 处理比内存大得多的数据,而不会降低性能或资源
③ 系统故障后可快速恢复到最近一个checkpoint
④ 支持PB级数据存储
⑤ 多线程架构,尽力利用乐观锁并发控制算法减少锁操作
⑥ 具有hot-caches能力
⑦ 磁盘IO最大化利用,提升磁盘IO能力
⑧ 其他
下结论:
① MongoDB默认的snappy压缩算法压缩比约为2.2-4.5倍
② zlib压缩算法压缩比约为4.5-7.5倍(本次迁移采用zlib高压缩算法)
,存储在MongoDB、MySQL、Es的磁盘占比≈1:3.5:6,不同数据会有所差距。
15W/s评估,预计需要4个分片。???
https://mongoing.com/archives/80037
https://www.yuque.com/jiangtengfei/mongodb/gk1c7x
列存储:Hbase, Cassndra, Hypertable
文档存储:MongoDB, CouchDB
key-value存储:Tokyo Cabinet /Tyrant, Berkeley DB, MemcacheDB
图存储:Neo4J, FlockDB
对象存储:db4o, Versant
xml数据库:Berkeley DB XML, BaseX
mysql 1000万以内,数据库性能可以,上亿条则数据库性能有降低,进行mysqly优化,当然和服务器性能有关系
oracle:几亿-几十亿,数据库性能有保障,商业付费高
mongodb: 单标存储的数据可以是 PB 级
B -> KB -> M -> G -> T -> PB -> EB -> ZB

命令
db.userInfo.totalIndexSize();
db.userInfo.find({name: /mongo/})
https://zhuanlan.zhihu.com/p/78062191
db.createCollection(“stu”, {capped:true, size:10})
capped 覆盖
mongoDB的shell内置js引擎可以直接执行js代码
function insert(object) {
db.getCollection(“db-text”).insert(object)
}
insert({age:32})
js脚本
var maxTime = Math.floor(new Date().getTime()/1000)
var minTime = maxTime - 24 60 60 * 300
//key要统计的时间
var nums = {0:0, 2: 0, 5:0, 30:0, 60: 0}
db.getCollection(‘carRecord’).find({catchTime:{“$gte”:minTime,”$lt”:maxTime }}).forEach(it=>{
var interval = it.createTime - it.catchTime
for(let key in nums){
if(interval>key*60){
nums[key]=nums[key]+1
}
}
})
nums
db.[documentName].remove([{name:”abc”}])
小技巧:直接删除大数据量集合比使用remove效率高很多
db.[documentName].update({查询器}, {修改器})
强硬的更新会用新的文档代替老的文档
save操作和insert操作区别在于当遇到_id相同的情况下
save完成保存操作
insert则会报错
db.[documentName].remove() 集合的本身和索引不会被删除
insertOrUpdate 操作
- 目的:查询器查出来数据就执行更新操作,查不出来就替换操作
- 做法:db.[documentName].update({查询器}, {修改器}, true)
upsert操作具有saveOrUpdate的功能,如果没有文档符合更新条件,则以更新条件和更新文档为基础创建一个新的文档。如果有符合更新条件的文档,则正常更新。创建新文档时会以条件文档作为基础,将修改器作用其之上。upsert操作是原子性的,高效的。
默认情况下当查询器查询出多条数据的时候默认就修改第一条数据
如何实现批量修改:db.persons.update({name:”33”}, {$set: {name:”333”}}, false, true)
批量更新只需将update的第4个参数设为true即可。
$addToSet与$each结合完成批量数组更新
db.text.update({_id: 1000}, {$addToSet: {books: {$each: [“js”, “DB”]}})
https://github.com/wovert/MongoDBTutorials
MongoDB对批量插入的支持是通过传递多个文档组成的数组到数据库来实现的。
$inc修改器:将指定属性的值增加特定的步长,如果键不存在则创建它。
$set修改器:用来指定一个键的值,如果不存在则创建它。
$push:数组修改器,如果指定的键存在,则向已有的数组末尾加入一个元素,键不存在则会创建一个新的数组。
这对于付费系统,安全性较高的系统是不可行的,此时对这些操作需要使用它们的安全版本。安全版本会在操作执行后立即运行getLastError命令,来检查是否执行成功。如果失败一般会抛出可捕获的异常,然后我们可以在代码中处理。
数据库会为每个MongoDB数据库连接创建一个队列,存放这个连接的请求,客户端新发送的请求会被放到队列的末尾。只有队列中的请求都执行完毕,后续的请求才会执行。即对于单个连接来说,请求都是顺序执行不存在并发问题,所以它总能读到自己写的东西。但对于不同的连接就有可能出现读取和写入不一致的问题,在驱动程序使用连接池时要特别注意此行为。
jb51.net/article/48218.htm
句柄数 io不高 入库慢?整体的并行connection 看到慢查询可能影响 线程被占用 索引建了没 db.stats() 锁的设置, 关闭update查看insert排查
范围分片的效率取决于选择的分片键。分片键考虑不周全会导致数据分布不均,这可能会削弱分片的某些优势或导致性能瓶颈。
使用带有collation : { locale : “simple” }选项的shardCollection命令可以对具备默认排序规则的集合进行分片。分片成功需具备下述条件:
集合必须具有索引,且该索引的前缀是分片键
索引必须具有{ locale: “simple” }排序规则
使用排序规则创建新集合时,请在分片集合之前确保满足这些条件。
当事务写入多个分片时,并非所有外部读取操作都需要等待已提交事务的结果在所有分片上可见。例如,如果提交了一个事务,并且在分片A上可以看到写1,但是在分片B上仍然看不到写2,在外部读取时设置读关注为[“local”]
从MongoDB 3.4版本开始,config servers必须部署为副本集架构 (CSRS)。???仅分片还不行
关于生产环境下分片群集的部署,请考虑以下事项: ???部署依赖和顺序,mongos组网
Deploy Config Servers as a 3 member replica set
将配置服务器部署为拥有3个成员的副本集。
Deploy each Shard as a 3 member replica set
将每个分片(Shard)部署为拥有3个成员的副本集。
Deploy one or more mongos routers
部署一个或多个mongos。
分片集群需要至少两个分片来分发分片数据。如果您计划在不久的将来启用分片,那么单个分片的集群可能很有用,但在部署时不需要启用。
部署多个mongos实例可支持高可用性和可扩展性。一个常见的模式是在每个应用程序服务器上部署一个 mongos实例。在每个应用服务器上部署一个 mongos实例可以减少应用程序和mongos之间的网络延迟。
ggg
https://docs.mongoing.com/replication
db.system.profile.find({}).limit(10).sort({ millis : -1 }).pretty()
查看正在处理的业务,判断imageRecord没有加索引而慢
4.0支持事务
https://blog.csdn.net/qq_33774822/article/details/84065571
- 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName=”Sameer”,Address=”8 Gandhi Road”)来实现更快的排序。
- 如果负载的增加(需要更多的存储空间和更强的处理能力) ,它可以分布在计算机网络中的其他节点上这就是所谓的分片。
- Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。???Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。
- GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。
- MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
| SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
|---|---|---|
| database | database | 数据库 |
| table | collection | 数据库表/集合 |
| row | document | 数据记录行/文档 |
| column | field | 数据字段/域 |
| index | index | 索引 |
| table joins | 表连接,MongoDB不支持 | |
| primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
文档是一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,
如果您拥有并使用多个集合,则必须考虑所有集合上所有索引的大小。索引和工作集必须能够同时装入内存。在一些有限的情况下,索引不需要装入内存。
从节点通过异步的方式将主节点oplog 应用至自己的数据集中。
复制集:副本集的最小推荐配置是一个包含三个数据承载成员的三成员副本集:一个主节点 和两个从节点。你可以选择使用一个仲裁节点。一个副本集最多可以有50个成员,但仅能有7个可投票成员。
从节点通过异步的方式将主节点oplog 应用至自己的数据集中。
一个MongoDB分片集群由以下组件组成:从MongoDB 3.6版本开始,每个分片必须部署为副本集架构。mongos充当查询路由的角色,为客户端应用程序和分片集群间的通信提供一个接口。Config servers(配置服务器)存储了分片集群的元数据和配置信息。
capped collections
Capped collections 就是固定大小的collection。
它有很高的性能以及队列过期的特性(过期按照插入的顺序). 有点和 “RRD” 概念类似。
Capped collections 是高性能自动的维护对象的插入顺序。它非常适合类似记录日志的功能和标准的 collection 不同,你必须要显式的创建一个capped collection,指定一个 collection 的大小,单位是字节。collection 的数据存储空间值提前分配的。
Capped collections 可以按照文档的插入顺序保存到集合中,而且这些文档在磁盘上存放位置也是按照插入顺序来保存的,所以当我们更新Capped collections 中文档的时候,更新后的文档不可以超过之前文档的大小,这样话就可以确保所有文档在磁盘上的位置一直保持不变。
由于 Capped collection 是按照文档的插入顺序而不是使用索引确定插入位置,这样的话可以提高增添数据的效率。MongoDB 的操作日志文件 oplog.rs 就是利用 Capped Collection 来实现的。
在{{system.indexes}}插入数据,可以创建索引。但除此之外该表信息是不可变的(特殊的drop index命令将自动更新相关信息)。
{{system.users}}是可修改的。 {{system.profile}}是可删除的。
https://blog.csdn.net/wengfuying5308/article/details/109436471
- mongos维护了片键的chunk(块)与分片的映射关系
- mongodb会在写入时建立一条日志journal。当系统异常崩溃时,通过日志replay未保存的数据,这个日志文件大约保存最近60s的日志。数据文件越60s写入一次到磁盘
推荐使用子集合作为关联集合的命名方式。比如:blog.posts和blog.authors
一边遍历一边保存,可能因为保存后的doc过大导致mongo把doc移到了集合的尾部,遍历两次。使用db.foo.find().snapshot()可以避免这个问题,但是会变慢
https://blog.51cto.com/raugher/1678704
如何查看锁的状态
db.serverStatus()
db.currentOp()
mongotop
mongostat
the MongoDB Monitoring Service (MMS)
db.currentOp 找一下对应的 opid
然后用 db.killOp 终止
secs_running
“”locks”” : { }, “”waitingForLock”” : false, “”lockStats”” : { “”Global”” : { “”acquireCount”” : { “”r”” : { “”$numberLong”” : “”4”” } } },
刷新mongo路由
Mongos在MongoDB架构中扮演一个查询路由器的角色,作为提供客户应用程序与数据库集合交互的接口,对应用程序而言,数据是整体且未被切分(分片)的,
对MongoDB有所了解的人都知道,MongoDB有一个让人头疼的全局锁(读写锁,允许并发读,而写会阻塞所有的读写),要命的是这个锁不是表级的,不是库级的,而是整个Server级别的,这让人听起来是不是非常的蛋疼。
300G数据,复制集replica,a、b、c仅ab各300G,如果分片就是ab、bc、ca各200G
WiredTiger通过MVCC实现文档级别的并发控制,即文档级别锁 可配置内存使用上限 WiredTiger支持对所有集合和索引进行Block压缩和前缀压缩
https://www.runoob.com/w3cnote/runoob-mongodb-update-3.html
https://www.it610.com/article/1281565893440061440.html
集群操作
MongoDB 还提供map-reduce操作来执行聚合。通常,map-reduce 操作有两个阶段:一个 map 阶段,它处理每个文档并为每个输入文档发出一个或多个对象,以及将map操作的输出组合在一起的reduce阶段。可选地,map-reduce 可以具有最终化阶段以对结果进行最终修改。与其他聚合操作一样,map-reduce 可以指定查询条件以选择输入文档以及对结果排序和限制。
Map-reduce 使用自定义 JavaScript 函数来执行 map 和 reduce操作,以及可选的 finalize 操作。与聚合管道相比,自定义JavaScript提供了很大的灵活性,但通常情况下,map-reduce比聚合管道效率低,而且更复杂。
map对每个文件过滤后第一次处理(这里是所有的归一),再reduce进行统计
$geoNear管道运算符利用地理空间索引。 gis支持。
聚合管道为map-reduce提供了一种替代方案,并且对于map-reduce的复杂性可能没有保障的聚合任务,它可能是首选的解决方案。
MongoDB 聚合管道由多个阶段组成。每个阶段在文档通过管道时转换文档。
{ user_id:A_id , bonus:[ { type:a ,amount:1000 }, { type:b ,amount:2000 }, { type:b ,amount:3000 } ] }
unwind操作(类似explode):
db.user.aggregate([ {$unwind:bonus} ]) //结果 {user_id : A_id , bonus:{type : a ,amount : 1000}} {user_id : A_id , bonus:{type : b ,amount : 2000}} {user_id : A_id , bonus:{type : b ,amount : 3000}}
db.user.aggregate([ {$match: {user_id : A_id} }, {$unwind:bonus}, {$match: {‘bonus.type’ : b} }, {$group: {_id : ‘$user_id’ , amount : {$sum : {‘$bonus.amount’}} }} ])
https://www.cnblogs.com/wangxiaoheng/articles/9699625.html
db.collection.aggregate([
{
$addFields: {
“TotalInstallments”: {
$sum: “$Installments.TotalPaid”
},
“TotalBalanceDue”: {
$subtract: [
“$TotalBilling”,
{
$sum: “$Installments.TotalPaid”
}
]
}
}
}
])
删除全部文档的name字段 db.users.update({},{$unset: {“name”:””}},{multi:true}) 增加全部文档的name字段 db.users.update({},{$set: {“name”:””}},{multi:true})
redact <- redaction 修订/校验,意思是对文档内容进行过滤,选择一些过滤或保留的信息 。
access level 存取等级 有三种:
- DESCEND 返回当前等级的文档,排除掉该等级下的内嵌等级文档;
- PRUNE 排除掉满足条件的当前等级及其下属等级的所有内容,而不再检查其内嵌文档是否还有满足条件的内容;
- $$KEEP 保留满足条件的当前等级及其下属等级的所有内容,而不再检查其内嵌文档是否有满足条件的内容;
与其他完全过滤不同,$redact聚合是对文档内部进行操作,返回的是经过删减的文档,而不是将整个文档都删除掉。该操作符常常和$cond一起使用。
$setIntersection表示将2个数组的交集中不同元素的个数,$cond就是一个三元表达式,此例中表示“如果交集元素的个数大于0,则值为为
DESCEND,否则为DESCEND,否则为
PRUNE”。对于此文档(ROOT级别)的最高级别的tags值为[“G”,”STLW”],此级别值为
$redact: {$cond: {
if: {
$gt: [ { $size: { $setIntersection: [ “$tags”, [“STLW”,”G”] ] } }, 0 ] },
then: “DESCEND”,
else: “PRUNE”
}
}
{
“_id” : 1,
“tags” : [ “G”, “STLW” ],
“year” : 2014,
“subsections” : [
{
“subtitle” : “Section 1”,
“tags” : [ “SI”, “G” ],
“content” : “Section 1” 为啥多了这个
},
{
“subtitle” : “Section 2: Analysis”,
“tags” : [ “STLW” ],
“content” : “Section 2”
}
]
}
https://blog.csdn.net/suyu_yuan/article/details/51773782
对于包含投影阶段($project或$unset或$addFields或$set)后跟$match阶段的聚合管道,MongoDB 将$match阶段中不需要在投影阶段计算的值的任何过滤器移动到投影前的新$match阶段。
如果序列中带有$sort后跟$match,则$match会移动到$sort之前,
当有一个$project或$unset之后跟有$skip序列时,$skip 会移至$project之前。
当管道的$redact阶段紧在$match阶段之后时,聚合有时可以在$redact阶段之前添加$match阶段的一部分。
$match+ $match合并 $skip+ $skip合并 $limit+ $limit合并 $lookup + $unwind 合并
管道阶段的 RAM 限制为 100M(10010241024字节)。如果某个阶段超出此限制,MongoDB 将产生错误。要允许处理大型数据集,可以在aggregate()方法中设置allowDiskUse选项。
变量可以容纳任何BSON 类型数据。要访问变量的 value,请使用带有前缀为 double 美元符号($$)的变量 name 的 string。
https://docs.mongoing.com/aggregation/aggregation-pipeline/aggregation-pipeline-optimization
BSON()是一种类json的一种二进制形式的存储格式,简称Binary JSON
它和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有JSON没有的一些数据类型,如Date和BinData类
//4字节带符合整数
db.mycol.insert({x:NumberInt(“3”)})
WriteResult({ “nInserted” : 1 })
变量可以容纳任何BSON 类型数据。要访问变量的 value,请使用带有前缀为 double 美元符号($$)的变量 name 的 string。

https://docs.mongoing.com/aggregation/aggregation-reference/sql-to-aggregation-mapping-chart
If your application frequently retrieves the address data with the name information, then your application needs to issue multiple queries to resolve the references. A more optimal schema would be to embed the address data entities in the patron data, as in the following document:
一对多用嵌套效率更高,但是嵌套不能太大
Instead of storing all of the reviews with the product, you can split the collection into two collections:
- The product collection stores information on each product, including the product’s ten most recent reviews:
The review collection stores all reviews. Each review contains a reference to the product for which it was written.
SELECT COUNT(*)
FROM (SELECT cust_id,
ord_date
FROM orders
GROUP BY cust_id,
ord_date)
as DerivedTable
db.orders.aggregate( [
{
$group: {
_id: {
cust_id: “$cust_id”,
ord_date: { $dateToString: {
format: “%Y-%m-%d”,
date: “$ord_date”
}}
}
}
},
{ 第二次group想到于select出结果再处理
$group: {
_id: null,
count: { $sum: 1 }
}
}
] )
集合操作对比
https://docs.mongodb.com/manual/reference/sql-aggregation-comparison/
db.characters.bulkWrite(
3
[
4
{ insertOne :
db.stores.createIndex( { name: “text”, description: “text” } ) 文本
db.stores.find( { $text: { $search: “java coffee shop” } } )
db.articles.aggregate(
[
{ $match: { $text: { $search: “cake” } } },
{ $group: { _id: null, views: { $sum: “$views” } } }
]
)
您可以在事务级别上而不是在单个操作级别上设置读取关注。要设置事务的已读关注点,
读取关注点的查询local从实例返回数据,但不保证数据已写入大多数复制集成员(即:可能会回滚)。
db.users.aggregate([
2
{ $project : { name:{$toUpper:“$_id“} , _id:0 } },
3
{ $sort : { name : 1 } }
4
])
然后$project创建一个名为name的新字段 抑制id字段。
https://docs.mongoing.com/mongodb-crud-operations/bulk-write-operations
An aggregation pipeline provides better performance and usability than a map-reduce operation.
https://docs.mongodb.com/manual/reference/method/db.collection.mapReduce/#db.collection.mapReduce
query planner分析 explain
https://www.cnblogs.com/zcy-backend/p/6914597.html
mongo进程可用有复制集角色、分片角色
MongoDB中的副本集是一组维护相同数据集合的 mongod进程。副本集包含多个数据承载节点和一个可选的仲裁节点。在数据承载节点中,有且仅有一个成员为主节点,其他节点为从节点。
写关注点级别来确认写操作;虽然在某些情况下,另一个mongod的实例也可以暂时认为自己是主节点。[1] 主节点会将其数据集合所有的变化记录到操作日志中,即oplog.。
从节点复制主节点的oplog,并将这些操作应用于它们的数据集,这样以便从节点的数据集能反映出主节点的数据集。如果主节点不可用,一个候选的从节点将会发起选举并使之成为新的主节点。
在某些情况下(比如您有一个主节点和一个从节点,但由于成本约束无法添加另一个从节点),您可以选择将一个 mongod 实例作为 仲裁节点添加到一个副本集中。仲裁节点参与选举但不持有数据(即不提供数据冗余)。
仲裁节点 永远只能是仲裁节点,但在选举过程中主节点也许会降级成为 从节点, 从节点也可能会升级成为主节点。
从节点复制主节点的oplog并异步地应用操作到它们的数据集。通过让从节点的数据集反映主服务器的数据集,副本集可以在一个或多个成员失败的情况下继续运行。
??没有执行完oplog使用哪个
副本集的副本成员会记录oplog中应用时间超过慢操作阈值的慢操作条目。这些慢oplog信息被记录在从节点的诊断日志 中,其路径位于REPL 组件的文本applied op: took ms中。
这些慢日志条目仅仅依赖于慢操作阈值。它们不依赖于日志级别(无论是系统还是组件级别)、过滤级别,或者慢操作采样比例。
复制延迟 指的是将主节点的写操作拷贝(即复制)到 从节点所花费的时间。一些小的延迟期可能是可以接受的,但是随着复制延迟的增长,会出现严重的问题,包括引起主节点的缓存压力。
从MongoDB 4.2开始,管理员可以限制主节点应用写操作的速度,目的是将majority committed 延迟保持在可配置参数flowControlTargetLagSeconds的最大值之下。
参数featureCompatibilityVersion (FCV) 设置为4.2并启用majority读关注点。也就是说,如果FCV不是 4.2 ,或者读关注点majority被禁用,那么启用流控制将不起作用。
启用流控制后,当延迟快接近 flowControlTargetLagSeconds
副本集在选举成功前是无法处理写操作的。如果读请求被配置运行在从节点 上,则当主节点下线时,副本集可以继续处理这些请求。
假设采用默认的副本配置选项,集群选择新主节点的中间过渡时间通常不应超过12秒。这包括了将主节点标记为unavailable、发起以及完成一次 选举的时间。您可以通过修改settings.electionTimeoutMillis 复制配置选项来调整这个时间期限。
由于诸如临时性的网络延迟等因素,集群可能会更频繁地发起选举,即使主节点在其他方面是健康的。这也许会增加w : 1 级别写操作发生回滚的可能性。
您的应用程序连接逻辑应该包括对自动故障转移和后续选举的容错处理能力。MongoDB 4.0和3.6兼容的驱动程序必须通过在 连接字符串中包含retryWrites=true来显式地启用可重试写。
默认情况下,客户端从主节点读取[1];然而,客户端可以定义一个读偏好 将读操作发送给从节点。
异步复制至从节点,意味着从节点读取返回的数据不能反映主节点上数据的状态。包含读操作的多文档事务必须使用读偏好primary。在给定的事务中所有操作都必须路由至相同的成员节点。???读偏好primary
然而,当一个事务写入多个分片时,并不是所有外部的读操作都需要等待提交的事务的结果在分片中可见。例如,如果提交了一个事务,并且在分片a上可以看到写1,但是在分片B上还不能看到写2,那么外部读关注为
副本集和分片集群支持变更流。变更流允许应用程序访问实时数据更改,而不需要跟踪oplog的复杂性和风险。应用程序可以使用变更流来订阅一个或多个集合上的所有数据更改。???变更流
分片是一种将数据分配到多个机器上的方法。MongoDB通过分片技术来支持具有海量数据集和高吞吐量操作的部署方案。
MongoDB通过分片来实现水平扩展。
oplog写也可能失败(我感觉不在内存和oplog在不同节点;oplog就像db操作的checkpoint对应的log,目的是checkpoint加快恢复),好处同步主备。
MongoDB分片集群包括以下组件:
分片:每个shard(分片)包含被分片的数据集中的一个子集。每个分片可以被部署为副本集架构。???
mongos:mongos充当查询路由器,在客户端应用程序和分片集群之间提供接口。从MongoDB 4.4开始,mongos可以支持 对冲读取(hedged reads)以最大程度地减少延迟。???对冲读
config服务器:config servers存储了分片集群的元数据和配置信息。
MongoDB使用分片键在各个分片之间分发集合中的文档。分片键由文档中的一个或多个字段组成。从MongoDB 4.4开始,您可以通过向现有键中添加一个或多个后缀字段来优化集合的分片键。???
您可以更新文档的分片键值,除非您的分片键字段为不可变_id字段。
MongoDB将分片数据拆分成块。每个分块都有一个基于分片键的上下限范围 。
均衡器通过在后台迁移各个分片上的块,来实现集群的所有分片中块的均匀分布。
对于包含分片键或复合分片键的前缀的查询,mongos可以将查询定位到特定的分片或一组分片。这些目标操作通常比广播到集群中的每个分片更有效。
通过分片技术将数据分布到分片集群中的各个分片中,每个分片只需存储数据集中的部分子集。随着数据集的增长, 通过增加分片的数量即可增加整个集群的存储容量。(通过均衡器使得新增加分片分摊数据)
虽然停机期间无法访问不可用分片中的数据子集,但是针对可用分片执行读取或写入操作仍然可以成功。???选择重要的才复制集
如果查询条件中没有包含拆分键或复合拆分键的前缀,mongos节点将执行广播操作,即查询分片集群中的所有分片。这些分散/聚集查询可能会变成长耗时的操作。???索引加快
数据库可以混合使用分片和未分片集合。分片集合被分区并分布在集群中的各个分片中。而未分片集合仅存储在主分片中。每个数据库都有自己的主分片。
您必须连接到路由器才能与分片任何集合进行交互。这包括分片和未分片的集合。客户端永远不要直接连到单个分片来执行读或写操作。
使用哈希索引解析查询时,MongoDB会自动计算哈希值,不需要应用程序来计算。尽管一系列分片键可能是“接近”的,但它们的哈希值不太可能在同一块上。基于哈希值的数据分发有助于更均匀的数据分发,尤其是在分片键单调更改的数据集中。但是,哈希分布意味着对分片键的基于范围的查询不太可能针对单个分片,从而导致更多集群范围的广播操作。
To evaluate if your cluster is performing scatter-gather queries, check if your most common queries include the shard key.
哈希分片以减少定向操作和增加广播操作作为代价,分片集群内的数据分布更加均衡。在哈希之后,拥有比较“接近”的片键的文档将不太可能会分布在相同的数据库或者分片上。
基于范围的分片是默认的分片方式。
您可以基于 shard key 创建分片数据的 zones
可以运用区域的一些常见开发模式如下:
- 在一个特定的分片集合中分隔一个特定的数据子集。
- 保证最相关的数据存储于与应用服务器地理上最相近的分片上。
- 基于硬件/分片硬件的性能将数据路由到分片。
分片下还可以有分区,分区下是trunk,分区不仅范围,还可以设置归档和最新数据,还可以基于应用和用户拆分数据
sh.addShardToZone(“shard0000”, “NYC”)
sh.updateZoneKeyRange(“records.users”, { zipcode: “10001” }, { zipcode: “10281” }, “NYC”)
The following are some example use cases for segmenting data based on Service Level Agreement (SLA) or Service Level Objective (SLO):
An application requires providing low-latency access to recently inserted / updated documents
An application requires prioritizing low-latency access to a range or subset of documents
An application that benefits from ensuring specific ranges or subsets of data are stored on servers with hardware that suits the SLA’s for accessing that data
Fast Tier (“recent”)
These are the fastest performing machines, with large amounts of RAM, fast SSD disks, and powerful CPUs.
The zone requires a range with:
- a lower bound of { creation_date : ISODate(YYYY-mm-dd)}, where the Year, Month, and Date specified by YYYY-mm-dd is within the last 6 months.
- an upper bound of { creation_date : MaxKey }.
Archival Tier (“archive”)
These machines use less RAM, slower disks, and more basic CPUs. However, they have a greater amount of storage per server.
The zone requires a range with:
- a lower bound of { creation_date : MinKey }.
- an upper bound of { creation_date : ISODate(YYYY-mm-dd)}, where the Year, Month, and Date match the values used for the recent tier’s lower bound.
基于tag分数据中心
sh.addShardTag(“shard0000”, “alfa”)
sh.addTagRange(
“
{ “datacenter” : “alfa”, “userid” : MinKey },
{ “datacenter” : “alfa”, “userid” : MaxKey },
“alfa”
)
sh.addTagRange(
“
{ “datacenter” : “bravo”, “userid” : MinKey },
{ “datacenter” : “bravo”, “userid” : MaxKey },
“bravo”
)
https://docs.mongoing.com/fen-pian
https://docs.mongodb.com/manual/tutorial/sharding-tiered-hardware-for-varying-slas/
Alternatively, starting in MongoDB 4.0.3, by defining the zones and zone ranges before sharding an empty or a non-existing collection, the shard collection operation creates chunks for the defined zone ranges as well as any additional chunks to cover the entire range of the shard key values and performs an initial chunk distribution based on the zone ranges.
Only pre-split chunks for an empty collection.
To split empty chunks manually, you can run the split command:
db.adminCommand( { split: “myapp.users”, middle: { email: prefix } } );
https://docs.mongodb.com/manual/tutorial/create-chunks-in-sharded-cluster/
oplog集合可以超过其配置的大小限制,以避免大多数提交点被删除。
副本集成员都包含一个oplog的副本,其位于local.oplog.rs集合中,该集合可以让副本集成员维护数据库的当前状态。
oplog中的每个操作都是幂等的。也就是说,对目标数据集应用一次或多次oplog操作都会产生相同的结果。
在 mongod 创建一个oplog前,您可以使用 oplogSizeMB 选项来定义oplog的大小。
为了保持幂等性,oplog必须将多次更新转换为单个操作。这会使用大量的oplog空间,而不会相应增加数据大小或磁盘使用。
记录在从节点上的慢操作应用程序有:
- 不受 slowOpSampleRate的影响;例如,所有的慢oplog条目被记录在从节点上。
- 不受 logLevel/systemLog.verbosity 级别的影响(或者systemLog.component.replication.verbosity 的级别);例如,对于oplog条目,从节点仅记录慢oplog条目。增加日志的冗余级别不会导致记录所有的oplog条目。
- 不会被捕获器抓取到,并且不受捕获级别的影响。
为了维护共享数据集的最新副本,副本集中的从节点成员可以从其他成员同步或复制数据。MongoDB中有两种形式的数据同步:初始化同步将完整的数据集填充至新成员;而复制会持续将变更应用到整个数据集上。
MongoDB默认是启用 journaling。日志可以防止在服务中断(如电源故障和意外重启)时发生数据丢失。???
https://docs.mongoing.com/replication/replica-set-oplog
分片键要么是一个索引字段,要么是一个存在于集合内所有文档中的复合索引字段。
MongoDB使用分片键值范围对集合中的数据进行分区。每个范围都定义了一个分片键值的非重叠范围,并且与一个chunk(数据块,下同)相关联。
一旦你对一个集合分片,那么其分片键就不可再改变
sh.shardCollection( namespace, key )
Specify a document {
- 1 indicates range-based sharding
- “hashed” indicates hashed sharding.
除非分片键字段是不可变的_id字段,否则您可以更新文档的分片键值。
- 如果集合为空,则sh.shardCollection()在分片键上创建索引(如果该索引尚不存在)。???
- 如果集合不为空,则必须先创建索引,然后再使用sh.shardCollection()。
- Starting in MongoDB 5.0, you can change your shard key and redistribute your data using the reshardCollection command.
- Starting in MongoDB 4.4, you can use the refineCollectionShardKey command to refine a collection’s shard key. The refineCollectionShardKey command adds a suffix field or fields to the existing key to create the new shard key.
Missing shard key fields fall within the same chunk range as shard keys with null values. For example, if the shard key is on the fields { x: 1, y: 1 }, then:
| Document Missing Shard Key | Falls into Same Range As |
|---|---|
| { x: “hello” } | { x: “hello”, y: null } |
| { y: “goodbye” } | { x: null, y: “goodbye” } |
| { z: “oops” } | { x: null, y: null } |
if the shard key is on the fields { x: 1, y: 1 }, you can find the documents with missing shard key fields by running this query:
| db.shardedcollection.find( { $or: [ { x: { $exists: false } }, { y: { $exists: false } } ] } ) | db.shardedcollection.find( { $or: [ { x: { $exists: false } }, { y: { $exists: false } } ] } ) |
|---|---|
https://docs.mongoing.com/fen-pian/sharded-cluster-components
https://docs.mongodb.com/manual/core/sharding-shard-key/
The ideal shard key allows MongoDB to distribute documents evenly throughout the cluster while also facilitating common query patterns.
The cardinality of a shard key determines the maximum number of chunks the balancer can create.
A shard key with low cardinality reduces the effectiveness of horizontal scaling in the cluster.
If your data model requires sharding on a key that has low cardinality, consider using an indexed compound of fields to increase cardinality.(值太少index意义不好,分片效果不好)
https://docs.mongodb.com/manual/core/sharding-choose-a-shard-key/
The balancer runs on the primary of the config server replica set (CSRS).
sh.disableBalancing(“students.grades”)
sh.disableBalancing()
db.settings.insertOne( { _id:”chunksize”, value:
config.shards.updateOne( { “_id” : “
By default, maxSize is not specified, allowing shards to consume the total amount of available space on their machines if necessary.
https://docs.mongodb.com/manual/reference/sharding/
用于—storageEngine选项设置inMemory;或者如果使用配置文件方式,则为storage.engine设置。
—dbpath,如果使用配置文件,则为storage.dbPath。 尽管内存存储引擎不会将数据写入文件系统,但它会在—dbpath中维护小型元数据文件和诊断数据以及用于构建大型索引的临时文件。
in-memory内存存储引擎将文档级并发控制用于写入操作。 因此,多个客户端可以同时修改集合的不同文档。
内存存储引擎要求其所有数据(包括索引,oplog(如果mongod实例是副本集的一部分)等)必须适合指定的—inMemorySizeGB命令行选项或中的storage.inMemory.engineConfig.inMemorySizeGB设置。
内存中存储引擎是非持久性的,不会将数据写入持久性存储。非持久数据包括应用程序数据和系统数据,例如用户,权限,索引,副本集配置,分片群集配置等。
除了独立运行外,使用in-memory内存存储引擎的mongod实例还可以作为副本集的一部分或分片群集的一部分运行。可以将使用内存存储引擎的mongod实例部署为分片群集的一部分。???
WiredTiger使用文档级并发控制进行写操作。 因此,多个客户端可以并发同时修改集合的不同文档。
对于大多数读写操作,WiredTiger使用乐观并发控制模式。
现在持久的数据充当数据文件中的检查点。 该检查点可确保数据文件直到最后一个检查点(包括最后一个检查点)都保持一致; 即检查点可以充当恢复点。MongoDB配置WiredTiger以60秒的间隔创建检查点(即将快照数据写入磁盘)。
https://docs.mongoing.com/cun-chu/cun-chu-yin-qing/in-memory-storage-engine
GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。
GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中。
GridFS 可以更好的存储大于16M的文件。
GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。
GridFS 用两个集合来存储一个文件:fs.files与fs.chunks。
每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。
大对象
https://www.runoob.com/mongodb/mongodb-gridfs.html
应该是之前没有正常被关闭,导致文件本锁住了。
解决办法:
1. 先把数据文件备份, —dbpath 的路径整个备份一下, 不然接下来的操作误操作了数据就丢失了
2. 运行修复命令:
mongod —dbpath /data/db —repair
全部删除来同步
索引的数量、分库、备份?
400G 100G, index加载400G;索引减少、64M 一个块(锁区域),往节点分发、均衡过程中有锁,副本数据算出, chunk迁移锁
分两层:1 主分片,块迁移(可关),;2 分片间主副,副还有监听节点(为了选举),oplog复制集,同步;
德阳是块迁移,内核调度无法支持
java线程锁,;mongo查锁的情况,操作查到;
查是不是index没有加
锁引坏了,建索引就锁表,background()
全量恢复;虚拟机备份;
数据损坏;
没有备份机制;华为1周;
https://zhuanlan.zhihu.com/p/27320848
???分库、index设置、锁分布式等
https://blog.csdn.net/weixin_34293902/article/details/92166894
缩减和增加 configsvr 节点 解决方法
# mongodump —port 21000 -d config #导出
# mongorestore —port 21001 -d configdump/config #导入
# mongorestore —port 21002 -d configdump/config #导入
https://zhuanlan.zhihu.com/p/70895268
锁机制
https://www.jianshu.com/p/18b8a81ae9d0?ivk_sa=1024320u
分布式锁
Index
对于经常变的index,一直停止index再批量更新,之后开启index;
另外一种相应档案数据放入ssd;
更高级还是多表,估计小修改表index小,再lookup
SSD
zone或tag
流水策略:如果有一些服务器比其他服务器更强大,我们可能希望让这些强大的服务器处理更多的负载。比如说:加入有一个使用SSD的分片能够处理10倍于其他机器的负载。我们可以强制将所有新数据插入到SSD,然后让均衡器将旧的块移动到其他分片上。
a. 为SSD指定一个标签:sh.addShardTag(“shard-name”,”ssd”)
b. 将升序键的当前值一直到正无穷范围的块都指定分布在SSD分片上:sh.addTagRange(“dbName.collName”,{“_id”:ObjectId()},…{“_id”:MaxKey},”ssd”) ,所有插入请求均会路由到这个块上,这个块始终位于标签的ssd的分片上。
c. 除非修改标签范围,否则从升序键的当前值一直到正无穷都被固定在这个分片上。可以创建一个定时任务每天更新一次标签范围:
use config
var tag =db.tags.findOne({“ns”:”dbName.collName”,…”max”:{“shardKey”:MaxKey}})
tag.min.shardKey = ObjectId()
db.tags.save(tag)
这样前一天的数据就会被移动到其他分片上了。
此策略的另一个缺点:需要修改才能进行扩展。如果写请求超出了SSD的处理能力,无法进行负载均衡。
https://zhuanlan.zhihu.com/p/338286940
运维
https://zhuanlan.zhihu.com/p/358043567
优化
https://www.zhihu.com/question/483701542
MongoDB:Es ≈ 1:6
25亿Es真实磁盘消耗30.5T,预计MongoDB磁盘消耗5T左右,考虑到未来数据增长,我们按照50亿数据计算,预计需要10T空间。2个分片,因此每个分片5T数据,最终确定单个mongod实例容器磁盘规格5T。
8CPU/8G内存/50G磁盘,一个代理和一个config server节点复用同一个容器。
2个分片及存储节点规格总结:2分片/16CPU、64G内存、5T磁盘。
客户端配置nearest ,实现就近读,确保请求通过代理转发的时候,转发到最近网络时延节点,也就是同机房对应存储节点读取数据。
弊端:如果是异地机房,B机房和C机房写存在跨机房写场景。如果A B C为同城机房,则没用该弊端,同城机房时延可以忽略。(复制跨机房才好,本地分片全集)
分片方式
为了充分散列数据到2个分片,因此选择hash分片方式,这样数据可以最大化散列,同时可以满足同一个_id数据落到同一个分片,保证查询效率。
预分片
MongoDB如果分片片建为hashed分片,则可以提前做预分片,这样就可以保证数据写进来的时候比较均衡的写入多个分片。预分片的好处可以规避非预分片情况下的chunk迁移问题,最大化提升写入性能。
注意事项:切记提前对ssoid创建hashed索引,否则对后续分片扩容有影响。
https://www.sohu.com/na/467051591_411876
“expireAt”: new Date(‘July 22, 2019 01:00:00’),
serviceExecutor: adaptive配置
mongodb默认的一个请求一个线程这种模式将会严重影响系统负载,该默认配置不适合高并发的读写应用场景。
脏数据太多容易造成一次性大量I/O写入,于是我们可以考虑把存储引擎cacheSize调小到50G,来减少同一时刻I/O写入的量
总体思想是让后台evict尽量早点淘汰脏页page到磁盘,同时调整evict淘汰线程数来加快脏数据淘汰,调整后mongostat及客户端超时现象进一步缓解。
触发checkpoint的条件默认又两个,触发条件如下:
固定周期做一次checkpoint快照,默认60s
增量的redo log(也就是journal日志)达到2G
checkpoint调整后的值如下:
checkpoint=(wait=25,log_size=1GB)
如果大家nvme ssd盘有同样问题,记得升级linux版本到3.10.0-957.27.2.el7.x86_64版本,升级后nvme ssd的IO能力达到近2G/s写入。
https://www.sohu.com/na/467051591_411876
完善的客户端均衡访问策略
MongoDB客户端访问路由策略由客户端自己指定,该功能通过Read Preference实现,支持primary 、primaryPreferred 、secondary 、secondaryPreferred 、nearest 五种客户端均衡访问策略。
https://mongoing.com/archives/80037
Change Streams性能优化实践
https://mongoing.com/archives/80259
该数据模型把相同characteristic特性的数十万数据合并到为一条数据,减少磁盘IO操作,整个读性能会有近百倍提升。
链接:https://www.zhihu.com/question/483701542/answer/2094430996
借助gperftools三方库中tcmalloc内存管理模块,实时动态调整tcmalloc内存Release Rate,尽早释放内存,避免存储引擎获取cache过程阻塞变慢。
https://my.oschina.net/u/4390731/blog/4929468
分片技术+仲裁节点+mongos路由+configsvr
安全
