MongoDB技術從0到1+

微信圖片_20200611091031.png
本文是陳仕在「青芒話生長」MongoDB徵文比賽的獲獎文章,下面咱們一塊兒來欣賞下。html

前言

偶然機會看到mongo中文社區辦了場徵文活動,以爲挺有意思的,雖然說本身還在成爲大佬的路上,但參與一下何嘗不可。因而就有了這篇文章。mysql

活動已規定了選題框架,我思索了小會兒,以爲從0到1+ 挺切合選題一,即聊聊如何由淺到深地學習MongoDB的核心技術。爲何是1+而不是1呢?由於我以爲0表明起點、原點,1表明走了一段路程,1+ 則表明在這方向上不斷地走下去。畢竟學無止境嘛~linux

怎麼聊這事呢?我本人是專職於database領域的,接觸MongoDB卻也不久,但有幸接觸到要與內核打交道的項目,因此研究了一段時間,也略有所得,因此此篇文章中也必然會談到學習MongoDB咱們能夠怎麼作起。既然從0開始,也必然少不了談Mongo的基本概念原理,因爲它是分佈式數據庫,也得談談分佈式技術的常見原理。這一趟下來,夠有談的了。固然單篇文章確實沒法說盡全貌,咱們不妨儘可能地從high-level的角度來認識和理解根本的抽象性、原理性的東西,這樣其實無論學什麼數據庫,我想會受益良多。git

入門使用

毫無疑問,最有用的文檔來自官方文檔,至關豐富,夠學一段時間了。可是若只是盯着文檔看幾周,估計用處不大,很容易忘。這種文檔就適合邊看邊學,邊看邊作。github

官方文檔連接:web

https://docs.MongoDB.com/redis

有一個網站db rank,專門給各種database排名,MongoDB一直很靠前,說明自有其魅力。簡單說,mongo是基於文檔的NoSQL數據庫系統,注意這裏的文檔可不是指word,excel那種概念的文檔,專指JSON文檔,{ k1: v1, k2: v2, … } 這個樣子的。咱們都知道,數據庫能夠在不一樣層面上進行分類,方便人去理解和對比。除了文檔型,還有kv, columnfamily, graph等。那還有沒有和mongo同處文檔這一類別的呢?固然有,我之前接觸過couchbase,Erlang寫的文檔型db,若是說要作性能比較,我倒以爲它們倆挺合適,雖然你們喜歡談mysql跟mongo比較。sql

在這裏仍是推薦一本書《MongoDB in action》,書能幫咱們系統地講清概念,起到官方文檔沒法有的做用。書雖着重於較老版本 3.0,但我想與目前的4.2 在使用上也不會相差太大,等熟悉了使用和基本原理再換別的看。mongodb

在這裏就不對各類命令使用作解析了,這個你們看文檔看書都能get到。談談一些有體會的點。數據庫

1.schema-free

schema-free說的是沒有schema或者schema很寬鬆,相對於關係型的relational schema。對database新手是否是對schema的概念也較模糊呢?我不知道中文是啥,不少詞彙感受就是英文表達順口些。我摘抄了一個定義[1]:

A database schema is the skeletonstructure that represents the logical view of the entire database. It defineshow the data is organized and how the relations among them are associated. Itformulates all the constraints that are to be applied on the data.

它是一個骨架,數據庫的骨架,定義了它的邏輯視圖,即從外面看它長什麼樣子。包括數據是怎麼組織的,是如何關聯的,有什麼樣的約束等。所以它是一種descriptivedetail,應該說在db設計階段就得有,幫助開發者創建mental view。

爲何要在這裏着重說schema ? 由於確實mongo schema長得不同,對習慣於關係型世界的人來說看着有點彆扭。其實也能夠說它是schema-less,就好像沒有schema似的,很隨意,想怎麼加field,加attribute都行,這樣的能力很顯然很是適用於不斷動態發展的業務。初期你不知道你業務有哪些字段,你只但願在將來有需求時想加就加,此時mongo在這個層面上很是契合。然而,關係型schema若提供這樣的能力代價就有些大了,相比於mongo。

2.適用場景

談到這一點,恐怕作數據庫的常常要回答的問題。一個用戶過來問他的業務能不能接MongoDB,你該如何回答他?他問得很簡單,可你答得卻不能很簡單,至少你得多問幾個問題,由於他沒有交待清楚。交待哪些呢?

是什麼樣的業務?數據量多大?

讀寫比例如何?讀寫QPS多大?

讀寫有何特徵,好比夜晚是低峯?

訪問模式(access pattern) ?

and so on

通常說來,業務是應該給出這些信息,咱們纔好判斷到底合不合適。畢竟市場上有這麼多db呢,若是每一個db都適用於全部場合,那整這麼多db幹嗎?大一統不香嘛。

可有些時候好比在公有云環境下,業務上下文可能仍是祕密,不想告訴你,或者說他也不太清楚/很差預估,此時能不能接呢?很差說,最好仍是在測試環境裏跑跑workload。前幾天看了TiDB前段時間分享的KeyViz,我有了點想法,若是有童鞋對這種 observability 工具備興趣,能夠一塊兒討論下。

據《MongoDB in action》裏所說,如下場景可接入mongo:

  • web app

這個範圍太廣了。不過確實MongoDB在web應用裏應用挺多,web應用特色本要求擴展性高,靈活豐富的查詢,動態地添加字段等

  • 敏捷開發

這裏主要強調的是因爲沒有固定的schema的優點使得很適用敏捷開發方法論

  • 分析型和logging

capped collection適合於放日誌數據,至於分析型我倒見很少,莫非還可比dedicated OLAP db更好?

  • caching
  • 可變schema

3.腳本搭建

我的建議呢,本身寫一個搭建集羣的腳本,方便一鍵生成,很是方便,而不要每次一個命令一個命令地敲。個人腳本供參考[7]

後面我會談到在快速建立定製化集羣的基礎上用gdb調試內核。

分佈式概念及原理

這一塊領域太大了!

MongoDB屬於分佈式數據庫,相比於單機數據庫,節點之間有了網絡距離,因而乎,各類不靠譜的事就會發生了(google一下"分佈式系統裏常見的8個fallacies")。我根據mongo實際狀況講點皮毛 _^^_ 更多有趣的資料務必參考DDIA[6],這個是迄今最通俗的版本。

我很是簡單地用本身的語言從背景、爲何須要它, Mongo怎麼作的三方面來談談,談到的詞彙建議讀者多多google。

===

共識協議(Consensus)

背景

簡單理解就是要多方達到一致。稍微接觸這塊的都知道raft,這個Stanford 教授  John Ousterhout 和其博士生 Diego Ongaro 弄出來的,已經在多種分佈式數據庫上應用瞭如TiDB, PolarDB。

固然業界還有其它協議,Lamport的Paxos(被應用到Chubby),Zookeeper的ZAB,MongoDB的pv1。

爲何須要它

簡單來看,當多個節點共同來作決定時,若是你說你的,我說個人,還怎麼決定啊?就像一羣人在房間開會,七嘴八舌,就是沒統一,最後這會只能白開了。同理在分佈式系統中,咱們需有一套規則讓各節點對事件以及結果達成一致,這樣才能正常運轉。這其實與現實世界模型是很吻合的。

Mongo怎麼作的

mongo用的是MongoDB pv1 ,是一種類raft 協議,不過它進行了豐富的擴展,如rs.conf()中就可配置各節點的priority,hidden, vote等屬性,有很是大的靈活性;增長了PreVote, DryRun等動做等。詳細細節讀者可參考相關文檔。

隔離級別/一致性(ACID/Consistency/CAP)

背景

這幾個概念有類似性,就放在一塊兒了。貌似分佈式系統裏咱們通常不談ACID,這是在單機關係型數據庫經常使用的詞彙,且這裏面的C 與分佈式系統所說的Consistency不是一回事!

CAP是Brewer 92年就提出的詞彙了,不少論文如今都不推薦使用這個詞彙,由於它頗有歧義;

在衆多論文裏,還有與一致性不少的詞彙,如

- causal consistency,因果一致性,Mongo中有

- linearizability,線性一致性,針對於single object的,始終讀到最新的數據

- serializability,串行化,強調多個事務操做多個object的,在關係型db屬最強的隔離級別

- strict serializability,linearizability + serializability,在google spanner中有提到

- sequence consistency: 順序一致性,比linearizability弱點,好比x86 CPU默認一致性是它,咱們常在C++ Memory Model裏見到`std::memory_order_seq`

在數據安全性方面,要有持久化的保證,通常經常使用技巧是按期作checkpoint,且有write-ahead log,這在WiredTiger引擎層有原生的支持。

爲何須要它

凡有副本,有讀寫,就必然存在讀可否讀到最新數據的問題,這就屬於一致性的問題。有的業務要求必須讀到最新寫入的數據,此爲strongconsistency,但有些業務不要求,那數據庫能夠放開這種強約束,因而有最終一致性eventualconsistency,即意味着給定必定的時間,最終各副本數據都會同樣的,這樣的實現比起強一致複雜度要低不少。

Mongo怎麼作的

關於一致性,我得談談當初本身存在已久的誤解。原來mongo裏的quorom 不是咱們常說的那種quorum !

之前深刻了解過Cassandra,和其C++產品Scylladb,它們的原型是amazon 的Dynamo,論文裏談到quorum模型:當有N個節點,若是寫大多數,即 W > N/2,讀也大多數 > N/2,則讀必定能夠讀到最新寫入的數據。然而mongo雖然也有majority的說法,但其內涵徹底是另一回事。

寫mongo時,客戶端只可能寫主,不可能寫從,這與leader-less 系統(無主系統,各節點都是對等的)就不同了,從是從主拉數據過去的;主從節點都在維護着一個majoritycommitted 的時間點,當寫已經到達大多數時,這個點就會向前推動;

當客戶端指定 readConcern: majority 時,能不能讀成功,就看發起操做的時間點是否是在majoritycommitted 時間點後面,若是是,則majority 讀就是成功的;

Mongo事務支持快照隔離,即事務可讀最近穩定的一個點,它多是老數據,可是它與其它數據是一致的,這樣就避免了讀寫衝突。

複製和故障冗餘(Replication, Fault Tolerance)

背景

在分佈式系統中,複製是提升可用性的重要、常規手段。在複雜分佈式環境下,總有個別組件就會崩,卡住,不響應,此時爲了避免影響用戶的請求,就須要將請求轉到正常的節點上,那數據就得有多份,要否則怎麼訪問先前訪問的數據呢?

故障冗餘是個經典概念了,分佈式裏的故障千奇百怪,軟件的,硬件的,人爲的;在典型的單主系統裏,主節點要是沒有,就會影響用戶的讀寫,因此在前一個的主節點沒了的那很短的時刻就必須有新的主來替代它,完美的時候用戶根本感覺不到切主。

爲何須要它

正如前面所說保證系統可用性,數據安全性。

Mongo怎麼作的

Mongo是單主系統,寫只能寫主節點,所以它有選舉機制,靠的是前面的所說的類raft協議。這是保證故障冗餘;

複製方面,從節點從主節點拉oplog,oplog就可理解爲raft裏的log,它反映了主節點的mutation,從節點將這在本地apply,就可達到與主節點一致的狀態。

很是詳細的說明見官方源碼[12]。

內核

我的接觸內核也沒多久,在此拋磚引玉。

內核其實分Server層和Storage Engine層,因爲Server接觸不完備,暫只講講引擎層的事兒。

存儲引擎

這裏有一份由doxygen生成的文檔[11],值得一閱。

引擎層技術可謂是數據庫系統的核心技術,裏面涉及了數據庫的核心原理的實現。首先咱們要明白,數據的組織能夠是多種方式,究竟哪一個方式好,在代碼未實現出來以前,恐怕還無法說。

明顯這裏咱們須要插拔的特性,數據庫層(也就是幹sql,cql,查詢優化,執行計劃等的)能夠靈活接入多種存儲引擎,這樣最後誰好誰差,比一比就知道了。因此引擎層必須很獨立,提供最原始的接口供上層調用便可,這也是計算機分層思想在數據庫領域的完美體現。

MongoDB引擎從3.x開始就是WiredTiger了,官方彷佛一直沒考慮把RocksDB兼容性的代碼放進去,因此MongoRocks是一個第三方的存在;固然還有一個in-memory引擎。

WiredTiger

這裏簡稱爲WT[8]。WT最初是一家由大佬 Michael Cahill 創立的,某一年被MongoDB收購,今後一直是mongo默認的存儲引擎。咱們能夠在這兒[2]看到WT的基本介紹,挺豐富的,沒事可多查閱。

WT首先是一個kv存儲引擎,類別上與Rocksdb一致,不過名氣確實小不少,緣由多是比較小衆,貌似只有mongo用,且代碼看着確實不太易讀;

引擎索引實現是B tree,而不是B+ tree,這一點網上也有很多的討論,至於爲什麼用B tree,據我所知:

1.mongo着重於提升point query性能,而非range query,這樣不像B+ tree那樣每次都得去葉子節點拿數據,平均來看,走更短的路徑;

2.優化讀多寫少的場景;

3.其餘。

WT API的使用

WT在mongo使用,其實基本的調用就那麼幾個:

1.建立鏈接conn

wiredtiger_open(home, NULL,"create,cache_size=**, transaction_sync=**, checkpoint_sync=**,...",&conn)

這在啓動時就需調用,生成一個指向db的WT_CONN,它做爲WiredTigerKVEngine的私有成員。

2.建立session

mongo裏的操做都有session上下文的,文檔裏的session,其實就對應引擎層的WT_SESSION ; 代碼裏爲了高效利用session,有個sessionCache供使用,不用每次都去open

conn->open_session(conn,NULL, "isolation=**", &session)

3.建立表/索引

當mongo層執行createCollection/createIndex時,即有:
sesssion->create(session, "table::access", "key_format=S,value_format=S"))

4.在session上建立cursor

session->open_cursor(session, "table:mytable", NULL,NULL,&cursor)

5.支持事務時,在session上開啓事務

session->begin_transaction(session, "isolation=**, read_timestamp=**,sync=**,...")

6.用cursor set/get key/value

用戶看到的json,mongo server層看到的BSON,其實在底層都轉成了(key, value) pair

cursor->set_key(cursor,"key")

cursor->set_value(cursor,"value")

cursor->update(cursor);

7.提交/回滾事務

session->commit_transaction(session,"commit_timestamp=**, durable_timestamp=**, sync=**,...")

session->rollback_transaction(session,NULL);

對於以上步驟,幾點澄清:

·WT API調用就像那種風格,特別明顯的是會有一參數char* config,裏面就用a=b這種格式來指定各類配置參數。雖然說挺原始的作法;

·有關時間戳的參數較爲複雜,須要深刻文檔;

·參數含義仍是得參考[2]。

時間戳機制

從官方文檔和視頻[14]中來看,從3.6開始引入 logical session,在WT 的update structure裏添加timestamp field等這些動做都是逐漸在爲支持事務、分佈式事務爲鋪路。

我爲熟悉MongoRocks對事務的支持接觸過WT的時間戳一些概念,目前還不能很系統地論述各個時間戳之間是如何運做的。這方面可多多參考[2] ,我不在此講了。

MongoRocks

聽名字想必也能猜獲得是與rocksdb有關,想到它也很天然,既然底層接kv engine,rocksdb又是kv型,徹底可接啊,正如MyRocks那樣。看源碼[3] stars也有300+,最初由開發者 Igor Canadi 及其餘實現了3.2, 3.4的MongoRocks版。項目被擱置一段時間,幾個月前 Igor Canadi 接受了wolfkdy 對MongoRocks 4.0 的MR[16],我在其中參與了相關PR提交如[4]。

4.0 mongo-rocks 驅動層的實現主要集中於事務部分,正如 Igor 所說,3.6.x以後,mongo的內部事務跳躍性大,若正確實現4.0版需很大一部分精力[5]。

MongoRocks 4.0 剛出不久,所以還需更多時間來穩定,好比以前由我發現的oplog讀取有空洞的問題[13],已被做者修復[15]。我的仍是很是期待Rocksdb能接入到Mongo的,相信會有比WT更亮的點!在這方面我的應該會投入更多時間,期待有更多國內開發者加入!

內核gdb調試

大型代碼,若是用gdb單步着來學習確定是不行的,單步只適用於調試bug的時候。我這裏談gdb調試用來幹嗎呢? get runtimepath !

我一直認爲,拿到一份大型C++項目,除了肉眼盯着代碼看半天瞭解code flow以外,用gdb bt 更是一大利器!在server端加一斷點,客戶端發一個命令過來,而後一bt ,馬上知道server 走的核心路徑,很方便!

劃重點:請用 >= 8.x 版本的gdb。好處是bt自帶顏色顯示,看着比之前舒服多了。

如下聊聊通常怎麼用。

首先啓動一副本集或分片集羣(取決於你關注哪一個),對主進行如下設置:

cfg=rs.conf();cfg.settings.heartbeatTimeoutSecs=3600; cfg.settings.electionTimeoutMillis=3600000;rs.reconfig(cfg)

這裏假設咱們要調試主。爲了防止調試時,默認的時間內就failover了,因此增大heartbeat,election的超時,這樣主就一直還是主(固然若想調試主從代碼的code,就不要這麼作了)

當咱們想看看insert命令的請求路徑時,

隨便看看代碼,去搜索一下insert關鍵字,相信不難發現有CmdInsert這樣的字眼。再仔細一看,發現它繼承一個基類,它還有個run方法,有感受的開發者其實這時就能猜一猜了:判定server收到insert請求時,極可能run要被調用!

因而乎可在run處加個斷點,或者咱們在grep中發現了insertRecords的字眼,更能斷定插入文檔時極可能走了這裏,因而有了這樣:

微信圖片_20200611091041.png

能夠繼續enter,這個路徑從libc.so start_thread 到run,到insertRecords 很長的,這一段路徑夠咱們分析是怎麼走的了。

一樣,對於find, update,delete都是相似手段。

對於事務操做,能夠去grep transaction字樣,也會發現能夠被做爲斷點的函數,遇到begin_transaction,commit_transaction, rollback_transaction實際上是很熟悉的函數名稱,適合加上斷點。

結語

MongoDB技術淺談在此,這方面知識量很是龐大,確不是由一篇文章能道盡的。對我本身而言,其內涵自己是迷人的,由於它是數據庫,它是分佈式系統,它還有許多毛病。儘管Mongo官方縮緊了協議,一些雲廠商無法玩高版本了。但我想,只要它仍是開源的,只要它代碼仍是真的,對工程師而言這仍然是一件欣慰的事吧。由淺入深,今後刻開始!

做者:陳仕

一名熱衷和專職於數據庫、分佈式、存儲技術的技術人,對linux內核、微處理器架構也很有興趣。工做初接觸redis/couchbase/scylladb等NoSQL數據庫,如今騰訊作mongo雲數據庫開發。業餘時間喜歡登山,研究論文,學習人文。

=== 我不是廣告

騰訊雲CMongo團隊致力於打造業務精緻的MongoDB雲服務,歡迎有興趣小夥伴加入,或者找我交流也行啊,哈哈

Email: sirchen@tencent.com

References

[1]https://www.tutorialspoint.co..._data_schemas.htm

[2]http://source.wiredtiger.com/

[3]https://github.com/mongodb-pa...

[4] https://github.com/mongodb-pa...

[5]https://github.com/mongodb -partners/mongo-rocks/issues/145

[6] MartinKleppmann DDIA: Designing data-intensive Applications

[7]https://gitee.com/cshi/codes/...

[8] https://github.com/wiredtiger...

[9]https://www.cnblogs.com/willi...

[10] 4.0事務淺析:https://mongoing.com/archives...

[11] 存儲引擎API:https://mongodbsource.github....

[12] 源碼對複製的詳細解釋:https://github.com/mongodb/mo...

[13]https://github.com/mongodb-pa...

[14]https://www.youtube.com/watch...

[15]https://github.com/wolfkdy/ro...

[16]https://github.com/mongodb-pa...

感謝國內領先的數據庫(MongoDB)及出海CDN(Akamai)服務提供商上海錦木信息技術有限公司對本次徵文的大力支持!

微信圖片_20200610112930.png

美國隊長

Mongoing中文社區( Mongoing.com)成這立於2014年,是大中華區得到官方承認的中文社區,通過社區志願者們的不斷努力,目前已經有超過2萬的線上及線下成員。中文社區由博客、線下活動、技術問答、社羣、官方文檔翻譯等版塊組成。截至2020年社區已成功舉辦數十場人數超百的線下活動,發表關於MongoDB應用優質文章百餘篇,相關合做單位已達20多家。

中文社區的願景是:爲廣大MongoDB中文愛好者建立一個活躍的互助平臺;推廣MongoDB成爲企業數據庫應用的首選方案;彙集 MongoDB開發、數據庫、運維專家,打造最權威的技術社區。

Mongoing中文社區公衆號: mongoing - mongoing

Mongoing中文社區http://mongoing.com/

微信圖片_20200611091048.png

上海錦木信息技術有限公司是國內領先的 MongoDB數據庫服務提供商,是 MongoDB廠商官方合做夥伴。

錦木信息始終堅守在數據技術領域紮實地實曨和前行,成爲國內 MongoDB領域的新興技術力量。服務的客戶普遍分佈於金融、電信、零售、航空等行業,助力用戶完成從傳統IT架構向互聯網架構的順利轉型。

2018年起,錦木信息與MongoDB中文社區創建了良好的合做關係,致力於共同建立繁榮的 MongoDB生態環境。

上海錦木信息技術有限公司http://www.jinmuinfo.com/

相關文章
相關標籤/搜索