大資料儲存:MongoDB實戰指南——常見問題解答

郭遠威發表於2014-12-26

 

鎖粒度與併發效能怎麼樣?

資料庫的讀寫併發效能與鎖的粒度息息相關,不管是讀操作還是寫操作開始執行時,都會請求相應的鎖資源,如果請求不到,操作就會被阻塞。讀操作請求的是讀鎖,能夠與其它讀操作共享,但是當寫操作請求資料庫時,它所申請的是寫鎖,具有排它性。

MongoDB在2.2之前的版本,鎖的粒度是非常粗的,它會鎖住整個mongod例項。這意味著當一個資料庫上的寫鎖被請求後,對mongod例項上管理的其它資料庫的操作都會被阻塞。2.2版本降低了鎖的粒度,引入了單個資料庫範圍的鎖,也就是說讀寫操作的鎖被限定在單個資料庫上,當一個資料庫被鎖住後,其它資料庫上的操作可以繼續被執行。儘管相對於全域性例項範圍鎖,資料庫範圍鎖效能有所提高,但是對於同一個資料庫大量的併發讀寫還是會有效能瓶頸出現,本書介紹的2.6版本仍然是資料庫範圍鎖,所以併發效能問題仍然存在。

在即將釋出的2.8版本中將會引入基於文件級別的鎖,相當於關聯式資料庫中的行級鎖,鎖的粒度更進一步變細。因此當一個寫操作發生時,只有涉及到的文件會被鎖住,如果寫操作涉及到整個集合,那麼將會產生一個集合鎖來鎖住整個集合,同理,如果寫操作涉及多個資料庫,仍然會有一個全域性例項鎖產生。

是否支援ACID事務?

經典ACID事務有四種特性即Atomicity,Consistency,Isolation和Durability。其中原子性保證了事務的操作要麼全部成功,要麼失敗後進行回滾,使資料庫回到原來的狀態;一致性保證了事務在開始之前和結束以後,資料庫中的資料完全符合所設定的各種約束和規則;隔離性保證了多個事務操作同一資料時,相互之間按照約定的隔離級別訪問和修改相同的資料,不同的關聯式資料庫會有不同的預設隔離級別;永續性保證了事務結束後,事務所涉及到的資料變化被持久的儲存在資料庫中,即使斷電重啟資料也會存在,並且是完整的。

MongoDB並不支援ACID事務特性,但是MongoDB支援在單個文件(記錄)上的原子操作,設計資料模型時,通過文件巢狀的方式也能解決關聯式資料庫中ACID事務特性所要求的大多數問題。例如,在關聯式資料庫中多條相關聯的記錄儲存,可以通過巢狀陣列或文件的形式作為一條記錄儲存在MongoDB中,這樣相當於實現了原子性。

 

 

記憶體對映檔案如何工作?

記憶體對映檔案是指呼叫作業系統的底層函式mmap( )將磁碟上的檔案對映到一個作業系統虛擬地址空間中,只是地址與地址之間建立一個對映關係,實際資料還在物理磁碟上,不在記憶體中。記憶體對映檔案是MongoDB儲存引擎管理資料的核心方法,一旦完成對映,MongoDB對這部分檔案資料的訪問,就好像在記憶體中訪問一樣,通過一個地址就能直接訪問了。

MongoDB利用記憶體對映檔案的方式管理和操作所有的資料,如果資料沒有被對映到記憶體中,則不能被訪問。對已經完成記憶體對映的檔案進行訪問時,如果發現資料不在記憶體中,則會發生缺頁錯誤,作業系統將通過對映好的地址關係找到在磁碟上的資料檔案並將它載入到記憶體中。

伺服器的記憶體多大合適?

MongoDB採用記憶體對映檔案的機制來加快資料的讀寫速度,使用作業系統自帶的虛擬記憶體管理器來管理記憶體,理論上MongoDB會佔用伺服器上所有的空閒記憶體,但實情況下的資料檔案總是遠大於實體記憶體的大小,況且可能會有新的程式執行在伺服器上,這也需要佔用記憶體,因此全部將資料檔案對映到虛擬地址空間是不可能的。

MongoDB在實際執行過程中,會有一部分經常被客戶端訪問的資料和索引,稱之為活躍“工作集”,如果能保證這部分“工作集”的資料常駐記憶體,系統效能將比較高效,否則,大量的磁碟I/O操作將會發生,降低系統效能。因此,伺服器的記憶體大小最少大於“工作集”資料的大小比較合適。當伺服器的空閒記憶體不足時,作業系統會根據記憶體管理演算法將最近最少使用的資料從記憶體中移除,騰出空間給有需要的資料。 

不支援join查詢怎麼辦?

Join查詢是關聯式資料庫中一種經典的多表聯合查詢的方式,但MongoDB並不支援這種操作。如果你想在多個Collection中檢索資料,那麼你必須做多次的查詢,如果覺得手動做的查詢太多了,你可以重設計你的資料模型來減少整體查詢的數量。

MongoDB中的文件可以是任何型別,我們可以輕易的對資料結構進行重構,這樣就可以讓它始終和應用程式保持一致,用一次查詢就能滿足需求。切記,避免用關聯式資料庫的思維來設計MongoDB的表結構。

複製集提供了資料冗餘功能為什麼還要用Journaling?

Journaling是特別有用的當資料庫遇到突然斷電等異常情況時,尤其是對只有單個節點的資料中心,它能使資料庫快速的恢復起來。Journaling類似關聯式資料庫MySql中的事務日誌功能,它與複製集的冗餘功能不一樣,後者更強調的是一種資料備份,而journaling偏向與資料庫災難恢復。關於Journaling的工作機制,請參考本書第5章。

什麼時候該用GridFS?

GridFS本質上還是基於MongoDB的collection和document等核心技術的,只是它會將大於16MB的檔案分割成許多小檔案,然後將這些小檔案儲存在相應的collection中。如果需要儲存的單個檔案的大小超過16MB,就應該用MongoDB自帶的GridFS系統,有的時候將大檔案儲存在MongoDB的GridFS中比直接存在作業系統的檔案系統中要更加高效;如果需要儲存的檔案數超過了作業系統中一個目錄下允許包含的檔案總數,則可以用GridFS系統;當你想要將你的檔案分散式部署在各個資料中心並提供冗餘保護時,可以用GridFS系統。

此外,當你的所有檔案大小都小於16MB時,不要用GridFS系統,因為將每個檔案儲存在一個document中往往會更高效。

分片叢集如何分發查詢請求的?

如何分發查詢請求在一個分片叢集上取決於叢集的配置和查詢語句本身。例如一個被分片的集合,有兩個欄位:user_id和user_name,其中user_id為分片的片鍵,當一個查詢語句利用user_id作為過濾條件返回結果時,mongos路由程式將先利用配置伺服器上的元資訊解析出需要從哪個或哪幾個片上獲取資料,然後直接將查詢請求定向到具體的片上,最後返回結果給客戶端;當一個查詢利用user_id作為過濾條件同時要求對查詢結果進行排序時,mongos先將查詢請求路由到具體的片上,並在各個片上完成排序,最後mongos將合併排序結果返回給客戶端;當一個查詢利用user_name作為過濾條件時,則查詢請求將被定向到所有的片上,mongos合併各片上查詢結果返回給客戶端。

複製集從故障中自動恢復要多久?

複製集從故障中恢復並選擇一個新的primary節點大約需1分鐘的時間。通常其它成員節點將會花大約10到30秒的時間傳送心跳包到發生故障的primary節點,判斷primary節點發生了故障;接著觸發一個選舉,大約再花10到30秒的時間選舉出新的primary節點,在選舉的過程中,複製集不能響應寫操作請求。如果配置了允許客戶端從其它secondary節點讀取,則在選舉的過程中複製集能夠響應客戶端的讀請求。

為什麼磁碟分配的空間大於資料庫中資料大小?

這主要有以下幾方面的原因:

(1)MongoDB儲存引擎採取預分配資料檔案機制,這樣能夠減少檔案系統的碎片。MongoDB將第一個資料檔案命名為<資料庫名>.0,第二個命名為<資料庫名>.1,依次類推下去。第一個檔案的大小為64MB,第二個為128MB,後面分配的檔案大小都是前面一個的兩倍,這樣會導致最後分配的資料檔案可能會有部分空間是沒有儲存資料庫資料的,因此會浪費一點磁碟空間。

(2)如果mongod例項是複製集的成員,則會在資料目錄下產生一個oplog.rs檔案,檔案中包含用來同步資料的操作日誌,類似於MySql中的二進位制日誌,這個檔案的大小約佔5%的磁碟空間,它是可以被重複使用的。

(3)資料目錄中還會包含journal檔案,在寫作的更改重新整理到資料檔案之前,用來儲存寫操作日誌,實現資料庫的恢復功能,類似於MySql中的redo日誌。

(4)當刪除一些集合或文件時,MongoDB儲存引擎會重用這部分資料空間,但是不會把這部分空間返還給作業系統,除非執行repairDatabase命令。

所以mongod例項佔用的磁碟空間大小總是大於資料庫中資料檔案的大小。

大資料儲存:MongoDB實戰指南

 

相關文章