- 求職 : Linux運(yùn)維
- 論壇徽章:
- 203
|
轉(zhuǎn)載自:http://www.mongoing.com/archives/2214
Mongodb 3.0支持用戶自定義存儲(chǔ)引擎,用戶可配置使用mmapv1或者wiredTiger存儲(chǔ)引擎,本文主要介紹Mongodb是如何使用wiredTiger數(shù)據(jù)庫(kù)作為底層的數(shù)據(jù)存儲(chǔ)層。目前還沒(méi)有讀過(guò)wiredTiger的源碼,本文的內(nèi)容都是基于wiredTiger官方文檔,以及Mongodb對(duì)wiredTiger封裝代碼,有問(wèn)題請(qǐng)指出。
wiredTiger引擎存儲(chǔ)布局
wiredTiger(簡(jiǎn)稱WT)支持行存儲(chǔ)、列存儲(chǔ)以及LSM等3種存儲(chǔ)形式,Mongodb使用時(shí),只是將其作為普通的KV存儲(chǔ)引擎來(lái)使用,mongodb的每個(gè)集合對(duì)應(yīng)一個(gè)WT的table,table里包含多個(gè)Key-value pairs,以B樹(shù)形式存儲(chǔ)。
以下是一個(gè)典型的使用WT存儲(chǔ)引擎的數(shù)據(jù)目錄布局(配置了directoryPerDB選項(xiàng),啟用了journal)
$tree
.
├── admin
│ ├── collection-11--5764503550749656746.wt
│ ├── collection-14--6907424972913303461.wt
│ ├── collection-16--6907424972913303461.wt
│ ├── collection-20--6907424972913303461.wt
│ ├── collection-8--6907424972913303461.wt
│ ├── collection-9--5764503550749656746.wt
│ ├── index-10--5764503550749656746.wt
│ ├── index-12--5764503550749656746.wt
│ ├── index-13--5764503550749656746.wt
│ ├── index-15--6907424972913303461.wt
│ ├── index-17--6907424972913303461.wt
│ └── index-9--6907424972913303461.wt
├── journal
│ ├── WiredTigerLog.0000000003
│ └── WiredTigerPreplog.0000000001
├── local
│ ├── collection-0--5764503550749656746.wt
│ ├── collection-2--5764503550749656746.wt
│ ├── collection-4--5764503550749656746.wt
│ ├── collection-6--5764503550749656746.wt
│ ├── collection-7--5764503550749656746.wt
│ ├── index-1--5764503550749656746.wt
│ ├── index-3--5764503550749656746.wt
│ ├── index-5--5764503550749656746.wt
│ └── index-8--5764503550749656746.wt
├── _mdb_catalog.wt
├── mongod.lock
├── products
│ ├── collection-6--6907424972913303461.wt
│ └── index-7--6907424972913303461.wt
├── sizeStorer.wt
├── storage.bson
├── WiredTiger
├── WiredTiger.basecfg
├── WiredTiger.lock
├── WiredTiger.turtle
└── WiredTiger.wt
WiredTiger*等文件存儲(chǔ)WT的一些配置信息。
local、journal、admin、products等每個(gè)目錄代表一個(gè)DB,DB里包含集合數(shù)據(jù)及集合的索引數(shù)據(jù),每個(gè)集合的數(shù)據(jù)對(duì)應(yīng)一個(gè)WT的table(一個(gè).wt后綴的文件),集合的每項(xiàng)索引也對(duì)應(yīng)一個(gè)WT的table。
journal目錄下存儲(chǔ)WT的write ahead log,當(dāng)服務(wù)crash時(shí),可通過(guò)log來(lái)恢復(fù)數(shù)據(jù)。
_mdb_catalog.wt里存儲(chǔ)了所有集合的元數(shù)據(jù),包括集合對(duì)應(yīng)的WT table名字,集合的創(chuàng)建選項(xiàng),集合的索引信息等,WT存儲(chǔ)引擎初始化時(shí),會(huì)從_mdb_catalog.wt里讀取所有的集合信息,并加載元信息到內(nèi)存。
集合名與WT table名的對(duì)應(yīng)關(guān)系可以通過(guò)db.collection.stats()獲取
mongo-9552 RIMARY> db.system.users.stats().wiredTiger.uri
statistics:table:admin/collection-10--1436312956560417970
也可以直接dump出_mdb_catalog.wt里的內(nèi)容查看,dump出的內(nèi)容為BSON格式,閱讀起來(lái)不是很方便。
wt -C "extensions=[/usr/local/lib/libwiredtiger_snappy.so]" -h . dump table:_mdb_catalog
sizeStorer.wt里存儲(chǔ)所有集合的容量信息,如文檔數(shù)、文檔總大小等,當(dāng)插入、刪除、更新文檔時(shí),這些信息會(huì)先cache到內(nèi)存,沒(méi)操作1000次會(huì)刷盤一次;mongod進(jìn)程crash可能導(dǎo)致sizeStorer.wt里的數(shù)據(jù)與實(shí)際信息不匹配,可通過(guò)validate()命令來(lái)重新掃描集合以訂正統(tǒng)計(jì)信息。
wiredTiger API
WT官方提供了C、java、python API,mongodb使用C API來(lái)訪問(wèn)WT數(shù)據(jù)庫(kù),主要包括3個(gè)核心的數(shù)據(jù)結(jié)構(gòu)。
WT_CONNECTION代表一個(gè)到WT數(shù)據(jù)庫(kù)的連接,通常每個(gè)進(jìn)程只用建立一個(gè)連接,WT_CONNECTION的所有方法都是線程安全的。
WT_SESSION代表一個(gè)數(shù)據(jù)庫(kù)操作的上下文,每個(gè)線程需創(chuàng)建獨(dú)立的session。
WT_CURSOR用于操作某個(gè)數(shù)據(jù)集(如某個(gè)table、file),可使用cursor來(lái)進(jìn)行數(shù)據(jù)庫(kù)插入、查詢操作。
如下是使用wiredTiger C API的示例,展示了如何向WT數(shù)據(jù)庫(kù)里插入數(shù)據(jù),更多示例參考這里。
#include
char *home = "WT_HOME";
int main(void)
{
WT_CONNECTION *conn;
WT_CURSOR *cursor;
WT_SESSION *session;
const char *key, *value;
int ret;
/* Open a connection to the database */
ret = wiredtiger_open(home, NULL, "create", &conn);
/* Open a session in conn */
ret = conn->open_session(conn, NULL, NULL, &session);
/* Create table if not exist */
ret = session->create(session,
"table:access", "key_format=S,value_format=S" ;
/* Open a cursor and insert key-value pair */
ret = session->open_cursor(session,
"table:access", NULL, NULL, &cursor);
cursor->set_key(cursor, "key1" ;
cursor->set_value(cursor, "value1" ;
ret = cursor->insert(cursor);
/* Close conn */
ret = conn->close(conn, NULL);
return ret;
}
上述示例包含如下步驟
wiredtiger_open()建立連接
conn->open_session建立session
session->create()創(chuàng)建access表,并指定key、value格式
session->open_cursor創(chuàng)建cursor,并插入key-value
訪問(wèn)結(jié)束后conn->close()關(guān)閉連接
wiredTiger in Mongodb
Mongodb使用wiredTiger作為存儲(chǔ)引擎時(shí),直接使用其C API來(lái)存儲(chǔ)、查詢數(shù)據(jù)。
wiredtiger_open
Mongodb在WiredTigerKVEngine構(gòu)造的時(shí)候wiredtiger_open建立連接,在其析構(gòu)時(shí)關(guān)閉連接,其指定的配置參數(shù)為:
配置項(xiàng) 含義說(shuō)明
create 如果數(shù)據(jù)庫(kù)不存在則先創(chuàng)建
cache_size=xx cache大小,使用Mongod cacheSizeGB配置項(xiàng)的值
session_max=20000 最大session數(shù)量
eviction=(threads_max=4) 淘汰線程最大數(shù)量,用于將page從cache逐出
statistics=(fast) 統(tǒng)計(jì)數(shù)據(jù)采用fast模式
statistics_log=(wait=xx) 統(tǒng)計(jì)數(shù)據(jù)采集周期,使用mongod statisticsLogDelaySecs配置項(xiàng)的值
file_manager=(close_idle_time=100000) 空閑文件描述符回收時(shí)間
checkpoint=(wait=xx,log_size:2G) 開(kāi)啟周期性checkpoint,采用Mongod syncPeriodSecs配置項(xiàng)的值
log=(enabled=true,archive=true… 啟用write ahead log,達(dá)到2G時(shí)觸發(fā)checkpoint
重點(diǎn)介紹下checkpoint和log2個(gè)配置項(xiàng),其決定了數(shù)據(jù)持久化的安全級(jí)別;wiredTiger支持2種數(shù)據(jù)持久化級(jí)別,分別是Checkpoint durability 和 Commit-level durability。
Checkpoint durability
wiredTiger支持對(duì)當(dāng)前的數(shù)據(jù)集進(jìn)行checkpoint,checkpoint代表當(dāng)前數(shù)據(jù)集的一個(gè)快照(或鏡像),wiredTiger可配置周期性的進(jìn)行checkpoint(或當(dāng)log size達(dá)到一定閾值是做checkpoint)。
比如WT配置了周期性checkpoint(沒(méi)開(kāi)啟log),每5分鐘做一次checkpoint,在T1時(shí)刻做了一次Checkpoint得到數(shù)據(jù)集C1,則在接下來(lái)的5分鐘內(nèi),如果服務(wù)crash,則WT只能將數(shù)據(jù)恢復(fù)到T1時(shí)刻。
Commit-level durability
wiredTiger通過(guò)write ahead log來(lái)支持commit-level durability。
開(kāi)啟write ahead log后,對(duì)WT數(shù)據(jù)庫(kù)的更新都會(huì)先寫(xiě)log,log的刷盤策略(通過(guò)trasaction_sync配置項(xiàng) 或者 begion_transaction參數(shù)指定)決定了持久化的級(jí)別。
mongodb的使用的持久化級(jí)別配置為
checkpoint=(wait=60,log_size=2G)
log=(enabled=true,archive=true,path=journal,compressor=snappy)
begin_transcation(“sync=true”)
具體策略為
每60s做一次checkpoint
開(kāi)啟write ahead log,當(dāng)log size達(dá)到2GB時(shí)做checkpoint;并自動(dòng)刪除不需要的log文件。
每次commit_transaction時(shí),調(diào)用fsync持久化已經(jīng)commit的log。
基于上述配置,mongodb可以保證服務(wù)crash時(shí),所有已經(jīng)commit的操作都能通過(guò)log恢復(fù)。
open_session
mongodb使用session pool來(lái)管理WT的session,isolation=snapshot指定隔離級(jí)別為snapshot。
conn->open_session(conn, NULL, "isolation=snapshot", &_session);
create table
創(chuàng)建數(shù)據(jù)集合的參數(shù)如下
配置項(xiàng) 含義說(shuō)明
create 如果集合不存在則先創(chuàng)建
memory_page_max=10m page內(nèi)存最大值
split_pct=90 page split百分比
checksum=on 開(kāi)啟校驗(yàn)
key_format=q,value_format=u key為int64_t類型(RecordId),value為WT_ITEM
數(shù)據(jù)集合的key為int64_t類型的RecordId,RerordId在集合內(nèi)部唯一,value為二進(jìn)制的BSON格式。
創(chuàng)建索引集合的參數(shù)如下
配置項(xiàng) 含義說(shuō)明
create 如果集合不存在則先創(chuàng)建
type=file,internal_page_max=16k,leaf_page_max=16k 配置樹(shù)節(jié)點(diǎn)大小
checksum=on 開(kāi)啟校驗(yàn)
key_format=u,value_format=u key-value均為WT_ITEM格式
索引集合的key、value均為二進(jìn)制數(shù)據(jù)。
table創(chuàng)建好之后,就可以往table
比如,往某個(gè)集合插入一組元素
db.coll.insert({_id: "apple", count: 100});
db.coll.insert({_id: "peach", count: 200});
db.coll.insert({_id: "grape", count: 300});
對(duì)應(yīng)一個(gè)coll的數(shù)據(jù)集合,其對(duì)應(yīng)的WT數(shù)據(jù)類似于
KEY VALUE
1 {_id: “apple”, count: 100}
2 {_id: “peach”, count: 200}
3 {_id; “grape”, count: 300}
以及基于id的索引集合,其對(duì)應(yīng)的WT數(shù)據(jù)類似于
KEY VALUE
“apple” 1
“peach” 2
“grape” 3
接下來(lái)如果在count上建索引,索引會(huì)存儲(chǔ)在新的WT table里,數(shù)據(jù)類似于
db.coll.ensureIndex({count: -1})
KEY VALUE
300 3
200 2
100 1
總結(jié)
Mongodb使用wiredTiger存儲(chǔ)引擎時(shí),其將wiredTiger作為一個(gè)KV數(shù)據(jù)庫(kù)來(lái)使用,mongodb的集合和索引都對(duì)應(yīng)一個(gè)wiredTiger的table。并依賴于wiredTiger提供的checkpoint + write ahead log機(jī)制提供高數(shù)據(jù)可靠性。
|
|