來自:
http://apan.me/index.php/2011/05/01/mongodb%E8%AE%BE%E8%AE%A1%E8%A6%81%E7%82%B9/
前陣子研究自動擴容(Auto-Scaling)時,特意瞭解了一下MongoDB,這裡簡單記錄一下其設計要點。
其官網的描述為:MongoDB是一個高效能、高擴充性的文檔型開來源資料庫,用C++實現,其主要特性為:
- 面向文檔(document-oriented storage)
- 支援索引
- 高可用性(replica sets)
- 平行擴容(auto-sharding)等
基本概念
- document:基本資料單元,相當於關係型資料庫中的一行記錄(Row);
- collection:相當於關係型資料庫中的表(table),但是是schema-free的table;
- namespace:每個collection有其對應的一個namespace。
儲存引擎
- 使用記憶體對應檔mmap實現,而32位機器受地址空間限制,所以單個執行個體最大資料空間僅為2.5G左右,64位機器基本無限制(128T),故建議使用64位機器部署。
- 每個資料庫由一個.ns中繼資料檔案,以及多個資料檔案組成(dbname.{0,1,2,……},以自增的數字為副檔名)。為了防止小資料庫浪費空間,MongoDB的資料檔案預設從16M開始,倍數層級增加,2G為單個資料檔案的大小上限。樣本如下:
- 每個資料檔案按extents(區段)組織。每個namespace可以包含多個extents,可以不連續。類似於資料檔案的倍數增長機制,每個namespace的extent大小同樣按倍數增長。每個資料檔案裡麵包含一個名為$freelist的特殊namespace,主要用於extent的回收管理(當collection被刪除後)。
- .ns檔案主要儲存該DB下所有collection的中繼資料資訊,例如該collection由哪些區段組成,有哪些索引等。每個區段的位置用如下資料結構表示:struct DiskLoc
{
int filenum; //the 0 in test.0
int offset; //position in file
}; //64bits
- 因為使用mmap實現,記憶體管理全部交給OS處理。
- 參考文獻:http://www.10gen.com/video/mongosv2010/storageengine
容災備份
Replica Sets基本原理
Replica Set在工作過程中,由一台唯一的master(a primary)和一台或多台slave(secondaries)組成。噹噹前master不可用時,該Replica Set通過選舉,選出一個新的slave作為新的master。
Replica Set組成
- Standard:標準節點,包含有所有資料備份,可以被選舉為master
- Passive:包含所有資料備份,但是不可以被選舉為master
- Arbiter:僅僅用於投票,不包含任何資料,一般是用於判斷網路狀態時使用的仲裁。
Oplog
Oplog是Operation Log的簡寫,相當於MySQL的bin-log,是MongoDB複製機制的核心。Oplog存在名為local的特殊DB中,其collection名為oplog.$main。該collection定長,可以通過啟動時通過—oplogSize參數設定。
每一條oplog包含有如下資訊:
ts:8位元組的時間戳記,由4位元組unix timestamp + 4位元組自增計數表示。這個值很重要,在選舉新primary時,會選擇ts最大的那個secondary作為新primary。
op:1位元組的操作類型,例如i表示insert,d表示delete。
ns:操作所在的namespace。
o:操作所對應的document。
Oplog是等冪的,只要按指定的先後順序,是可以被多次執行的。例如一個自增(inc)操作,在oplog裡面記錄是一條set操作。
同步
當一個新備機啟動時,先從主機做一個全量文檔同步,然後查詢master的oplog,並執行
選舉演算法
- query all others for their maxappliedoptime
- try to elect self if we have the highest time and can see a majority of nodes
- if a tie on highest time, delay a short random amount first
- elect (selfid,maxoptime) msg -> others
- if we get a msg and our time is higher, we send back NO
- we must get back a majority of YES
- if a YES is sent, we respond NO to all others for 1 minute. Electing ourself counts as a YES.
- repeat as necessary after a random sleep
|
自動擴容
Auto-sharding機制
- Config Servers:儲存整個叢集的中繼資料,包括每個Shard Server的基本資料,以及其儲存的Chunk資訊。每個Config Server擁有這些中繼資料的全量備份。多個Config Server資料一致性通過二段式提交保證。如果某一個Config Server不可用,則整個叢集的中繼資料變為唯讀狀態,不可修改。
- Router:路由器主要負責接收Client的請求,並將請求轉寄到對應的Shards,如有需要,還需合并結果集再返回Client。
- Shard Servers:資料服務器,每個Shard一般是一個Replica Set。
路由表
Collection |
Minkey |
Maxkey |
location |
Users |
{name : 1} |
{name : miller} |
Shard0 |
Users |
{name : miller } |
{name : Ness} |
Shard1 |
Users |
{name : Ness } |
{name : Ogden } |
Shard2 |
Users |
{name : Ogden } |
{name : 1} |
Shard3 |
Chunks
一個Chunks表示該collection下的一個連續分區,其分區範圍為[minkey, maxkey)。當一個Chunks大小增長至200M時,會自動的分裂為2個Chunk,如有必要,其中Chunks還會被遷移至其他Shard。
在選擇Shard Keys時,需考慮該key是否能將資料均衡打散。例如以name作為key,如果很多人具有相同的name,則很有可能導致無法分裂及遷移。
案例分享
Foursquare宕機事件
foursquare去年10月,曾發生了一次長達11個小時的宕機事件。其主要原因是MongoDB的Shard演算法不均導致。其詳細分析參考Fenng的文章:Foursquare長達11小時的宕機。
這裡補充一下,因為MongoDB儲存引擎使用mmap,其記憶體管理全部由OS處理,而OS是按page(頁)來處理的,如果一個page裡麵包含多個小documents,僅刪除該page裡的某一個document並不能釋放該頁記憶體,故在該事件的處理過程中,最終花費了近5個小時執行repairDatabase。