MongoDB问题集锦

一、基础

1、mongodb是什么类型的数据库?

mongodb是一个基于document的NOSQL数据库,每条数据的结构为BSON形式。mongodb不能支持join和事务,支持索引(组合索引、唯一索引等)和丰富的查询条件,单条document的写操作是原子的。mongodb使用“replica set”架构模式来提高数据的可用性,避免数据丢失和自动failover机制;其sharding模式,允许将较大的数据集均匀分布在多个mongod上,实现架构的水平扩展。

2、mongodb支持tables吗?

mongodb中collection的概念等同于RDBMS的table,但是存储方式完全不同。mongodb中最高层是database,然后是collection,每个collection保存一类结构相似的documents。但是因为mongodb是“schema-free”(模式自由的),所以每条document的数据结构可能并不完全相同,理论上它们可以完全不同,即可以拥有不同的Fields;不过对于table而言它的所有column都已经被严格限定,每条数据的结构完全一致;collection的schema不需要预先定义。

3、mongodb数据库是否有schema?**

mongodb使用动态的schema,创建collection是不需要定义schema,即不需要定义数据结构,比如字段列表、字段类型等等。任何一个document都可以随意的增加或者删除fields,这主要归因于BSON数据结构(类JSON,Key-value模式)。不过根据application的设计需要,每个collection在数据结构上应该基本相似,而不是千差万别;我们应该将不同类型的数据存于不同的collections中,而不是混淆在一个collection中,尽管这样不会带来问题。

4、mongodb是否支持SQL?

mongodb使用自己的查询机制,不适用SQL,即mongodb不是SQL标准的产品,不过基于mongodb之上,社区提供了SQL-LIKE引擎,比如Drill,它允许开发者使用SQL查询mongodb数据。

5、mongodb是否需要很大的内存?

对内存的消耗取决于mongodb使用的存储引擎,目前mongodb支持MMAPv1和wiredTiger两种存储引擎。

MMAPv1:不需要,可以运行在少量内存的机器上;mongodb将会尽可能多的使用空闲内存,这有mmap机制决定(系统级别),所以系统资源监控时通常会显示mongodb消耗了大量的内存,不过这种消耗是动态的,如果其他进程需要内存,那么mongodb将会让步一些内存。这是有操作系统的虚拟内存管理机制决定,这意味着mongodb尽可能多的消耗空间内存,在需要时也会swap数据到磁盘。对于MMAPv1引擎,较大的内存空间可以极大的提升性能。

wiredTiger:这是一个类似于bigtable(基于列族,LSM)的存储引擎,mongodb会使用wiredTiger cache;默认情况下(3.2+版本),wiredTiger cache为物理内存为:MAX(60% * RAM -1G , 1G);如果物理内存超过10G,那么cache的大小为RAM的50%。不过具体消耗多少内存,我们仍然可以通过配置文件来限定。我们都曾经抱怨,mongodb过于消耗内存,所以wiredTiger引擎将改变这一情况!不过对于架构师而言,需要认识到一个权衡的艺术:内存的消耗,带来了实质的性能提升;有限的内存,必然会降低性能,对于mongodb而言,较大的内存对性能的提升,是立竿见影的,无论是哪种引擎。

6、如何配置cache的大小?

根据上述介绍,MMAPv1引擎不能配置cache的大小,因为底层是基于操作系统的MMAP机制,它将尽可能的消耗空间的内存。不过这并不会带来严重的问题,因为内存的分配将是动态的。

对于wiredTiger引擎而言,可以通过如下方式限定cache的大小(单位:G): storage: engine: wiredTiger wiredTiger: engineConfig: cacheSizeGB: 8

7、mongodb是否需要额外的、应用层的cache?

不需要,在mongodb中,document在数据库中的表现态与内存中非常相似,即在database中和内存中都是JSON格式,对于应用而言,不需要额外的引入一个cache层保存documents。这与RDBMS不同,数据在数据库中和内存中的表现态完全不同,这意味着从数据库中读取的数据需要经过一些列的解析转换成内存态的objects,所以额外的引入cache来保存数据可以有效的较少数据解析,对性能提高有一定的帮助。

8、mongdb是否处理缓存?

是,mongodb将最近使用的数据、索引信息、工作区数据都保存在内存中,即cache,这些数据可以服务于多个query,以提高性能。不过mongodb并不会cache查询结果。

9、write操作是立即写入磁盘还是延迟进行?

MMAPv1引擎中,write操作会首先被写入到journal日志文件,然后写入到内存(映射文件中);大家都知道频繁的fsync操作会严重影响磁盘的并发读写能力,所以journal日志为每100毫秒同步一次,数据文件每60秒同步一次;其中journal日志文件用于恢复数据,最坏的情况下丢失100毫秒内的write数据;如果关闭了journal功能,那么最多丢失60秒内的数据(数据可能处于损坏状态)。可以通过“storage.syncPeriodSecs”和“storage.journal.commitIntervalMs”来设定这两类文件的fsync的频率。

wiredTiger,采用了不同的存储机制(LSM树,bigtable模型),write操作将数据写入journal文件,然后cache在内存中;每隔60或者内存中有2G数据需要写入磁盘时,mongodb将会创建一个checkpoints并将内存数据写入一个磁盘文件中(每次flush都生成一个文件,然后定期整理和merge它们);journal文件默认100毫秒同步一次磁盘(参数配置同上),当journal文件尺寸达到100M时,mongodb会重新生成一个新的。(参见【mongodb存储引擎原理】)

由此可见,mongodb中write操作通常是“延迟的”,这也意味着有数据丢失的风险;“replica set”架构模式可以有效避免数据丢失的可能,此外开发者还需要使用“write concern”相关的参数来限定write操作的担保级别。

10、当删除document时,mongodb是否也从磁盘中移除?

是的,当执行remove操作后,此document将被不会在存在于数据文件中。

11、为什么mongodb的数据文件这么大?

mongodb采用预分配机制来创建数据文件,以避免文件系统的碎片;可以通过设定“storage.smallFiles”来指定使用小文件(测试环境中)。参见【存储原理】

12、什么时候使用GridFS?

当document的尺寸超过16M时,你需要将数据保存在GridFS中。因为普通的collection中每条document不得超过16M,否则无法存储。GridFS作为一个分布式文件系统,它比本地文件系统更加优秀的地方包括:1)支持较大数据集,集群数据冗余策略 2)可以保存除文件之外的其他metadata,对于本地文件系统而言是无法做到的 3)文件在GridFS中是分段存储(chunks)

如果你需要修改文件的内容,而且需要保证原子性,则不适合GridFS,因为GridFS将文件分成多个chunks保存,每个chunks就是一个document,所以无法确保原子性。建议GridFS保存那些只读的数据。

如果你的文件小于16M,比如图片、网页、文本等,则不需要保存在GridFS中,完全可以将数据以BinData(即字节码)保存在普通的collection中即可。

二、并发

13、mongodb如何支持并发的?

mongodb提供了多种粒度的lock机制:global、database、collection级别;在wiredTiger中还支持document级别的锁。mongodb中包含读、写两种锁,允许多个reader并行读取数据,但是writer是排他的,同一个collection任何时候只能有一个writer获取锁。

14、cursors与write操作

对于MMAPv1,cursor遍历collection时,同一个document可能会返回多次,有点类似于“幻读”;这归因于mongodb底层存储的原因,在cursor读取数据期间,如果cursor之前的某个document因为update导致document尺寸变大进而超过allocation空间(powerOf2SizeAllocation),那么此document原空间被回收,并在数据文件中重新分配存储空间保存此document数据,那么此document的物理位置就有可能位于cursor之后,如果cursor中没有使用索引的话,有可能会导致此document再次被scan并返回给client。为了避免此问题,可以使用snapshot方法,snapshot不能在sharding collection中使用,而且它也会带来性能问题。插入和删除document不会导致上述问题。

snapshot只是将数据查询(包括索引)转换成_id索引的顺序读取documents,因此在snapshot中将不能使用sort()和hint()限定符,如果使用了索引,且需要保证此索引值不会被修改。

wiredTiger引擎不会出现cursor与write操作的隔离问题。

15、是否可以人工对document设计padding来避免update时对document的移动(即空间重新分配)?

对于MMAPv1引擎,默认使用“power of 2 Sized Allocation”机制,这是一种目前被验证的比较良好的padding策略,通常情况下application不需要再人为padding。对于开发者而言,所能做的padding就是确保documents的那些没有值的field填充一个合适的默认值即可;比如document中插入时没有字段“modified”字段,那么在update时添加此字段,为了避免“移动”,可以在插入document时即增加modified字段和默认值。

16、mongodb使用何种类型的lock?

mongodb使用多粒度锁,比如global、database、collection级别,对于wiredTiger引擎还支持document级别的lock。每个级别的锁分为read和write锁,其中read为共享锁(S),write为排它锁(X),意向共享锁(IS)和意向排它锁(IX)表示read或者write操作获取更细粒度的资源的意图,通常而言,如果lock是分级的、Tree结构的,那么在高级别资源上使用意向锁,在最终级别的资源上使用“共享锁”或者“排它锁”。如果你已经了解“意向锁”的原理,或许理解起来将会更加容易。

在mongodb中,资源的锁定级别(或次序)依次为:Global –> Database –> Collection –> Document,粒度逐渐变小,并发能力依次更强。 如果想获取collection的write锁(X,排他锁),那么必须在依次在Global 和相应的Database上获取“意向排它锁”(IX),如果这两个级别上的IX锁获取成功,才能在Collection上“尝试”获取X锁。对于同一个数据库,可以同时被IS、IX两种模式锁定,但是X锁不能与其他模式兼容,S锁只能与IS模式兼容。关于意向锁的兼容性,参见:

因为锁的颗粒度有多个级别,通过意向锁对资源访问路径进行标记,对于解决锁冲突是非常必要的。锁的获取是公平的,如果锁被占用,那么获取锁的请求将被队列化,不过为了优化吞吐能力,当一个锁请求被准许,那么同时其他相容的锁请求也会一并被准许。例如,当X锁释放时,锁队列中有如下请求:

IS->IS->X->X->S->IS

按照严格意义的FIFO(公平锁)顺序,只有开头的“IS”、“S”两个请求被准许(相容);不过mongodb为了优化并发能力,将会把队列中所有与IS相容的请求全部准入(并从队列中移除),即IS、S、IS、IS;当上述锁请求全部释放lock以后(有计数器决定,0),此时即使队列中又有了新的IS或者S锁请求,但不会再次准许它们,而是开始检测队列的头部,首个锁请求为X,不过此锁是排他锁,所以逐个准许。

17、mongodb中锁的粒度是怎样的?

对于wiredTiger而言,使用了乐观的并发控制,在global、database和collection级别,只使用意向锁;当存储引擎检测到两个操作有锁冲突时,其中一个操作将会透明的重试(CAS方式,tryLock)。对于有些特殊的操作,仍然会使用排它锁,比如删除collection仍会在database上获取X锁。乐观的并发控制主要是针对documents数据的操作。

对于MMAPv1引擎,在3.0之后即支持collection级别的锁,此前只支持database级别,因此新版本的并发能力将会提升很多。比如一个database中有多个collection,那么这些collection可以同时接收write、read请求;不过database上的排它锁会阻止collections上的读写操作。

18、如何查看mongod上的锁状态?

可以使用shell方法db.serverStatus()、db.currentOp(),或者使用mongotop、mongostat脚本查看。这与mysql等都非常相似,在操作列表中,可以查看操作的id,也允许使用db.killOp()方法终止指定的操作。

19、read或write操作锁是否会yield?

在某些情况下,read和write操作会让步锁。比如一些执行耗时的update、delete或者query,操作执行一段时间或者每隔一定数量的documents(100条)之后会yield一次,允许其他操作获取lock并执行,那么当前操作重新尝试获取锁(锁请求队列尾部);yield操作减轻的锁请求的“饥饿”程度。

对于某些特殊的操作,即使执行的时间较长,但是为了避免并发问题,仍然不会yield,比如index文件的加载和刷新等。

20、shading架构中是如何并发的?

sharding通过将collections数据分布在多个mongod实例上提高集群整体的并发能力和吞吐量,允许每隔servers(比如mongos,mongod)并行的执行读写操作。lock被应用在每个单独的shard节点上,而不是在整个cluster上,即每个mongd单独维护各自的locks,在mongod上的操作不会干扰其他实例上的lock。

21、replica set集群中primary是如何并发的?

对于replica set,所有的write操作均首先在primary上执行,操作也会被写入到local数据库的oplog中(特殊的capped collection)用于其他secondary同步,因此每个write操作将会同时锁定collection的数据库以及local数据库,以保证数据的一致性。注意lock发生在primary上,对于secondary仅仅是同步oplog和应用数据操作。

22、那么secondaries上是如何并发的?

在replica set架构中,mongodb不会直接在secondaries上执行write操作,多个secondaires冰心的同步(批量)primary中的oplog,然后在各自的本地apply这些操作。secondaires在应用write操作时不允许read操作执行,其严格根据oplog中操作的顺序执行write操作(同步,回放)。

23、mongodb是如何并发执行javascript脚本的?

这主要对mapreduce、aggregate操作有影响,在2.4之后版本中,mongodb使用了V8引擎允许一个mongod同时允许多个javascript脚本,并发能力极大提高;不过在2.4之前的版本,mongodb为了避免脚本的并发执行,只能同时执行一个javascript操作。

24、mongodb提供了何种担保级别(数据一致性)?

mongodb在并发读写操作中,提供了如下几种担保级别:

  • write操作对单个document是原子性的,比如更新一个document中的多个fields,要么全部更新成功,要么都不更新;那么对于reader而言永远不会看到只有部分更新成功的document。对于单个mongod实例而言,发生在同一个document上write操作是序列化的,read也是序列化的。
  • 由query限定条件约束正确性,find()和update()操作只会影响那些符合条件的documents。
  • read操作中使用sort,结果的顺序并不会因为并发写入而破坏。

mongodb尽管对单个document提供了较强的担保,不过read和write操作可能会访问任意数量的documents,mongodb不会对多个documents的操作提供事务性,也不会将一个将writes操作彼此隔离(和RDBMS数据库相比,事务操作提供了多种数据隔离级别,但mongodb并没有):

  • “Non-point-in-time”,假如一个read操作开始与t1并开始read,此后t2时间,一个write操作对某个document提交了update。reader或许会看到更新后的document,即read操作并不是读取t1时刻的snapshot数据,而是“fuzzy”(模糊的),不像mysql事务那样提供了严格的数据隔离级别,所以“幻读”、“不可重复读”是一定会发生的。(所以,使用mongodb执行“select for update”操作将是不安全的)
  • “Non-serializable”,针对不同的document,read和write操作是非序列化的,参看上文中的“锁与并发”。
  • 对于MMAPv1,read数据时如果有updated或者delete操作,可能会有些数据“丢失”,即read开始时这些documents符合匹配规则,但是在read期间可能因为被update而不再符合匹配条件。(还是归因于事务与隔离级别)

25、read操作是否会看到那些update尚未提交到disk的数据?

mongodb 3.2版本引入了“readConcern”选项(仅对wiredTiger引擎有效),这与先前版本中的“read Preference”不同,针对“replica set”架构模式;readConcern有2个可选值:local和majority。

“local”表示read操作可以读取那些已经write成功但或许尚未durable的数据;数据已经在本地执行成功,写入了内存,但或许尚没有在replica set的多个members上同步成功,这些数据仍然有“rollback”的风险,比如primary失效之前,此write操作只在primary上写入成功但尚未在多个secondaries上同步,这意味着primary失效后,此write数据将丢失。“local”选项使read操作可以读取本地任何可见的数据,无论“write concern”为任何级别、journal配置。(有“脏读”的可能,即read到的数据可能在此后的某个时间“不见了”)

“majority”表示read只会读取那些已经在多数派的secondaries上写入成功的数据,不会出现“rollback”现象。

对于“local”,将有可能出现如下行为:

  • 在write操作执行的结果返回给客户端之前,mongodb允许read操作看到此write的变更。
  • 因为replica set中primary失效、failover或者整个集群故障(失去电力),read操作先前看到的数据可能会“roll back”,即在此read将不再存在;语义等同于事务中的“不可重复的读”。

三、sharding集群

26、在sharding collection创建之后我是否可以修改shard key?

不能!shard key是sharding collection数据分布的依据,不能修改。如果需要变更shard key,需要“清洗”数据,即将现有collection数据全量读取,逐个修改,并写入到使用新的sharding key的collections中。

27、在sharded数据库中使用unsharded collections将会出现什么情况?

sharded数据库将那些“unsharded” collections数据保存在primary shard节点上。

28、mongodb是如何在shards之间分布数据的?

首先需要对database和collection开启sharding,否则数据不会在shards之间分布,而只会贮存在此数据库的primary shard节点上。对collection开启sharding后,mongodb将根据shard key以及sharding算法将不同ranges的数据迁移到不同的shards中,cluster会自动负载均衡。【参见sharding集群】

29、当chunk在迁移时,此chunk上的某个document被修改了,将会发生什么?

在chunk迁移期间,反正在此chunk上的read、write都将在“old” shard上进行,当chunk迁移成功后,集群将会在config servers中修改chunk的从属关系(改为“new” shard),此后所有的read、write将会在new shard上进行。在迁移期间,old shard负责收集发生在此chunk上的update操作,并在迁移的最后阶段将这些变更操作增量同步给new shard,并block那些发生在old chunk上的其他write操作,直到chunk迁移完毕。

30、当某个shard节点失效,将会query发生何种影响?

sharding collection的数据分布在多个shards上,如果某个shard失效,那么query将返回error,在默认情况下不允许返回“不完整”的结果集。

不过为了兼容这种问题,client可以在query中指定“partial”选项,表示如果某个shard不可访问,它允许接受“不完整”的数据集,那么query将会忽略不可用的shard而继续进行。

31、mongodb是如何在shards之间分发query的?

  • 如果查询中指定了shard key,则mongos根据config servers中的metatada信息计算出query所需要访问的shards(即那些持有shard key值的chunks所在的shards),并将query请求转发给这些特定的shards,并有mongos负责merge并将结果返回给client。
  • 如果查询中指定了shard key,且使用了sort、limit、skip等限定符,同1)mongos将query转发给特定的shards,最终结果有mongos负责merge、sort等,并将有序而且完整的结果返回给client。
  • 如果查询中没有指定shard key,mongos将会把请求发送给所有的shards,并有mongos负责merge-sort。

32、在sharding环境中,mongodb是如何对query结果排序的?

如果在query中指定了sort限定符,那么query将会被发送给特定的shards,且每个shard负责sort那些符合query的结果数据,并返回给mongos,由mongos负责最终的merge-sort。

33、我已经开启了sharding,并且新增了一个shard节点,但是为什么data仍然不能在两个shard上动态平台?

首先,确认你是否在sharding collection上指定了shard key,且一切配置没有问题。然后你需要知道,shard迁移数据的单位是chunk,一个chunk大小为64M(默认),如果你的数据小于64M,事实上chunk不会迁移和分裂。

此外,集群系统为了避免过于“激进”的迁移,collection中的数据至少有10个chunks时才会触发balancer;在这之前,如果你只能人工干预chunks的分布。

34、是否可以移除“moveChunk”目录下的旧数据文件?

可以,“moveChunk”目录下的文件是本机的chunks迁移到其他shards之后的旧文件数据,这些数据可以被删除。

35、mongos是怎么使用connections的?

每个client都维护一个(或者多个,线程池)与mongos的链接,每个mongos实例也维护一个与集群所有shards建立链接的连接池;client与mongos之间,以及mongos与shard之间,都是使用线程池模式。(每个shard一个连接池,如果shard是“replica set”结构,那么此连接池与replica set中所有memebers保持链接)

36、为什么mongos总是保持链接处于open?

mongos使用一系列的连接池与每个shard通讯,即使client数量减少,连接池也不会收缩。这会导致那些没有客户端使用的mongos仍然与shards保持大量的链接,如果mongos不再需要,应该restart它或者关闭它,以关闭这些链接。

37、管理员如何处理那些迁移失败的chunk?

这种情况,不需要人工干预。

38、mongos在什么时机检测config servers的变更?

mongos实例会在本地内存中保存一份config数据库的cache,config 数据库中保存了sharding集群的所有metadata,比如chunks与shard的映射关系、collection与chunks的从属关系等等。mongos采用延迟更新metadata的方式,即当mongos请求shards数据时告知“metada过期”,才会向config server同步新的metadata。当然管理员也可以在mongos上执行“flushRouterConfig”指令来强制刷新,不过对于client而言尚没有任何方式来控制刷新metadata。

39、mongos中的“maxConns”参数是什么意思?

在mongos配置文件中“maxIncomingConnections”以及启动命令行参数“–maxConns”用来限定mongos所能接收的最大客户端连接数。

40、在sharding系统中indexes是如何影响query的?

如果query中不包含shard key,那么mongos必须将query发送给所有的shards,类似于“scatter/gather”操作。每个shard将会依次(in turn)使用shard key或者其他更高效的index来填充query结果。

如果query中指定了shard key或者包含shard key的左前缀,mongos可以将query路由到特定的几个shards即可,然后使用索引高效的填充query。

41、shard key的值可以随机生成吗?

可以,随机的值可以提高数据的散列能力。

42、是否可以将_id字段作为shard key?

可以,而且通常情况下,id是默认的shard key。不过需要知道id的生成算法,其值为自增的。

四、replication

43、mongodb replication模式能支撑多少节点?

3.0之后的版本中,每个replica set架构模式可以支持最多50个节点,先前版本只能支持12个。

44、primary是什么意思?

replica set模式中,只有primary节点能接收write操作。

45、secondary是什么意思?

即read-only节点,负责数据备份和提供read操作。

46、replica set中自动failover需要多久?

通常情况下,failover+选举primary需要1分钟。对于所有的members而言,需要消耗1-~30秒用于断定primary已经无法访问,此时间有“electionTimeoutMills”参数决定(参见setting);如果primary是失效,secondaries则选举自己为primary,最终集群将会根据“权重”、“数据跟进程度”选择合适的primary;在选举期间,cluster是只读的。选举可能会耗时10~30秒。在3.2+版本,mongodb缩减了选举的时间,参见“选举改进”。

47、尽然replication已经提供了数据冗余能力,为什么还需要journaling?

journaling特性用于crash时快速数据恢复,如果没有journaling,crash之后需要执行“repairs”或者“全量数据同步(full resync)”,这两个操作通常比较慢,而且“repairs”也不可靠。

journaling在电力失效时用于保护数据是非常有用的,特别是党replica set处于同一个data center中(同一个机房或者局域网内)。使用journaling,在集群失效时,可以非常安全的重启它们而无需人工干预。

不过它需要一些额外的开支,当write操作时需要首先写入journal日志文件,对read操作并无影响。在productin环境强烈建议开启。

48、当使用“write concern”限定时,write操作会durable吗?

会的,write concern只是提供了write操作的状态通知机制(ACK),它对write操作是否durable并无影响。默认情况下,write操作总是在replica set中多数节点上写入成功后才把状态返回给Client。

不过write concern提供了多种“担保级别”,如果你使用了较低的级别(比如primary),在极端情况下可能会出现“rollback”情况,即数据丢失!

49、replica set需要多个arbiters(仲裁者)?

通常的配置中或许我们不需要arbiters。arbiters不从primary上同步、备份数据,只是在选举时可以投票。为了能够更好的选举,replica set中需要大多数members处于有效状态,arbiters就是用于“补充”大多数(majority)投票者的作用;选举者通常是奇数,如果你有偶数个members,可以增加一个arbiter达成“奇数”。

50、arbiters与其他members交互什么信息?

首先arbiters不会接收collections的实际数据,它与其他members交互如下信息:

  • aribiters与其他members建立链接时需要提交“credentials”(认证证书),mongodb默认使用keyfiles,只有认证通过后arbiters才能加入集群。【参见security】
  • 投票信息

51、什么样的members才会在选举中投票?

除了“votes”为0的members,其他的都可以投票,包含“delayed”、“hidden”、“secondary-only”(权重为0的,不会被选举为primary)类型的members,当然arbiters一定会投票。不过事实上,“votes=0”与members的类型是两个参数,对于任何类型的members如果votes=0将不能投票。

五、存储引擎

52、什么是存储引擎?

它的职责就是如何存在磁盘上储数据、管理数据;很多数据库,可以支持多种存储引擎,每种引擎可以在特定的使用场景下更加优秀,比如某个引擎可能在大量read操作中性能更高,还有引擎在大量write操作时支撑的并发量更大等等。比如mysq支持mysiam、innodb等。

52、对于mongodb默认的存储引擎是什么?

mongodb目前支持MMAPv1和wiredTiger,在3.0+版本中支持wiredTiger,在3.0之前的版本默认引擎为MMAPv1;在3.2以及之后的版本,默认引擎为wiredTiger。

53、在replica set中,是否可以混合使用存储引擎?

可以,replica set中不同的members可以使用的不同的存储引擎;不过需要为了避免运维的不必要麻烦,仍然建议使用统一的配置。

54、对于wiredTiger,我应该设定多大的cache?

wiredTiger为了提升read性能,将使用本地cache。在3.2+版本中,wiredTiger默认的cache大小为MAX(RAM * 60% – 1G,1G);如果系统的RMA超过10G,cache的大小与3.0版本一致:50%的RAM。较大的物理内存对提升wiredTiger性能有极大的帮助。

55、什么是内存映射文件?

memory-mapped文件是操作系统通过mmap()系统调用将文件数据载入内存,mmap()将文件映射到虚拟内存的一个区域(region)。内存映射文件是MMAPv1引擎的核心。mongodb通过内存映射操作文件内容就像它们在内存中一样,因为整个文件操作全部基于系统调用,mongodb不需要太多的文件、内存管理,性能较高而且实施简单。

56、内存映射文件是如何工作的?

内存映射将数据文件直接以逐字节对应的方式映射到一块虚拟内存中,当mongodb访问documents时将数据文件映射到内存中,那些不被访问的文件不会被映射。一旦映射,文件与内存的映射关系,就允许mongodb就像操作操作内存一样直接与数据文件交互。

57、为什么实际数据文件的总尺寸比database中documents的总量要大?

  • 数据文件预分配(preallocated):mongodb采用预分配数据文件的方式来避免文件系统的磁盘碎片,即“data files”中可能有一定的文件是未被使用的。对于测试环境,我们可以使用“smallFiles”选项来减少预分配文件的大小。
  • oplog:对于replica set架构模式,oplog是必须的,用来保存write操作的记录以供secondaries同步;所以oplog也会占用一定的存储空间,默认为磁盘大小的5%。
  • journal:操作日志文件,用于故障恢复。相当于binlog,占用空间较少。
  • padding与空记录:mongodb在为每个document分配存储空间时,默认采用“PowerOf2SizedAllocatied”,所以document实际占用空间要比它的内存字节数要多一些。此外,一个document的删除或者因为更新导致document空间重新分配时,将会在data files中留下一个“间隙”,这个间隙空间或许会被此后的insert重用;但最终这部分空间仍然会被占用。我们可以执行“comact”指令来重新整理这些“空隙”。

58、什么是“working set”?

working set表示操作的整个过程中所访问的数据总和,通常是整个数据的一个子集,不过实际的working set大小依赖于当前实际的数据库使用情况。比如,你运行一个query,它可能需要scan整个collection,那么working set将会包含整个collection。因为物理内存是有限的,会导致working set中一部分documents被“page out”(swap到磁盘cache中),或者被操作系统从内存中移除;此后mongodb再次访问这些文档时,将会发生“page fault”。

59、什么是“page fault”?

这是mmap中一个概念,“page fault”的数据并不在内存中,将会导致mongodb从实际的data files中读写数据。通常情况下,操作系统的“page faults”发生在当物理内存耗尽时,部分内存页数据将会被swap到磁盘中。如果此后有空闲的内存,操作系统将会把磁盘上的pages重新载入内存,不过如果内有空闲内存,操作系统必须:

  • 找到内存中那些已经过期的(stale)或者长时间没用的pages,将它们写入内存。
  • 然后将需要的pages从磁盘中重新加载到内存(如果pages在swap cache中,则直接载入;否则需要重新访问数据文件)。

这个过程,与直接从内存中读取pages相比,消耗更长的时间,特别是在一个繁忙的操作系统上。

60、soft和hard page faults有什么区别?

在MMAPv1引擎中,当mongodb访问的数据不在内存中时即为“page faults”;“hard” page faults是mongodb必须从磁盘中访问数据文件(swap cache中的pages已经删除),“soft” page fault表示从swap cache中加载页数据即可。

六、索引

61、每次insert之后都需要执行createIndex()方法吗?

肯定不是,createIndex只需要执行一次即可,此后每次insert时将会自动为此document创建索引条目。

63、我如何知道collection中有哪些indexes?

通过“db..getIndexes()”方法查看

64、如何判定index的大小?

使用“db..stats()”。

65、如果index无法被全部保存在RAM中将会发生什么?

随着数量的增大,index的总尺寸可能会超过RAM;此时mongodb必须从磁盘中读取index文件,这将比从RAM中读取慢很多。index和working set均会占用内存,所以较大的内存对提升索引访问效率非常有效。

66、如何知道query是否使用了index?

mongodb提供了类似于SQL的方式:explain()方法,可以查看query使用index的情况。

67、如何判定需要为哪些fields创建索引?

有多种因素决定是否对字段建立索引,比如“selectivity”(选择性)、index内存使用量,以及index是否可以兼顾在多种queries等等。

68、index是怎么影响write操作的?

任何修改indexed字段的update都会导致索引重新调整,如果你更新document导致文件size增大需要重新分配存储空间的话,mongodb需要更新所有的包含此字段的indexes信息:因为document的存储位置变更,那么与此document有关的indexes条目都需要重新指向新的位置。

如果你的应用有大量的write操作,且创建了大量的indexes,那么将会对系统的write性能带来影响。

未经允许不得转载:氢网 » MongoDB问题集锦

支付宝扫码打赏 微信打赏

欢迎点击上方按钮对我打赏

分享到:更多 ()

评论 抢沙发

评论前必须登录!