一、基礎
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的大?。▎挝唬篏):
java代碼
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在并發讀寫操作中,提供了如下幾種擔保級別:
1)write操作對單個document是原子性的,比如更新一個document中的多個fields,要么全部更新成功,要么都不更新;那么對于reader而言永遠不會看到只有部分更新成功的document。對于單個mongod實例而言,發生在同一個document上write操作是序列化的,read也是序列化的。
2)由query限定條件約束正確性,find()和update()操作只會影響那些符合條件的documents。
3)read操作中使用sort,結果的順序并不會因為并發寫入而破壞。
mongodb盡管對單個document提供了較強的擔保,不過read和write操作可能會訪問任意數量的documents,mongodb不會對多個documents的操作提供事務性,也不會將一個將writes操作彼此隔離(和RDBMS數據庫相比,事務操作提供了多種數據隔離級別,但mongodb并沒有):
1)“Non-point-in-time”,假如一個read操作開始與t1并開始read,此后t2時間,一個write操作對某個document提交了update。reader或許會看到更新后的document,即read操作并不是讀取t1時刻的snapshot數據,而是“fuzzy”(模糊的),不像mysql事務那樣提供了嚴格的數據隔離級別,所以“幻讀”、“不可重復讀”是一定會發生的。(所以,使用mongodb執行“select for update”操作將是不安全的)
2)“Non-serializable”,針對不同的document,read和write操作是非序列化的,參看上文中的“鎖與并發”。
3)對于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”,將有可能出現如下行為:
1)在write操作執行的結果返回給客戶端之前,mongodb允許read操作看到此write的變更。
2)因為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會自動負載均衡?!緟⒁妔harding集群】
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的?
1)如果查詢中指定了shard key,則mongos根據config servers中的metatada信息計算出query所需要訪問的shards(即那些持有shard key值的chunks所在的shards),并將query請求轉發給這些特定的shards,并有mongos負責merge并將結果返回給client。
2)如果查詢中指定了shard key,且使用了sort、limit、skip等限定符,同1)mongos將query轉發給特定的shards,最終結果有mongos負責merge、sort等,并將有序而且完整的結果返回給client。
3)如果查詢中沒有指定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交互如下信息:
1)aribiters與其他members建立鏈接時需要提交“credentials”(認證證書),mongodb默認使用keyfiles,只有認證通過后arbiters才能加入集群?!緟⒁妔ecurity】
2)投票信息
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的總量要大?
1)數據文件預分配(preallocated):mongodb采用預分配數據文件的方式來避免文件系統的磁盤碎片,即“data files”中可能有一定的文件是未被使用的。對于測試環境,我們可以使用“smallFiles”選項來減少預分配文件的大小。
2)oplog:對于replica set架構模式,oplog是必須的,用來保存write操作的記錄以供secondaries同步;所以oplog也會占用一定的存儲空間,默認為磁盤大小的5%。
3)journal:操作日志文件,用于故障恢復。相當于binlog,占用空間較少。
4)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重新載入內存,不過如果內有空閑內存,操作系統必須:
1)找到內存中那些已經過期的(stale)或者長時間沒用的pages,將它們寫入內存。
2)然后將需要的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.<collection>.getIndexes()”方法查看
64、如何判定index的大???
使用“db.<collection>.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性能帶來影響。
新聞熱點
疑難解答