溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MongoDB從入坑到入迷的過程是怎樣的

發(fā)布時間:2021-09-29 10:23:20 來源:億速云 閱讀:102 作者:柒染 欄目:數(shù)據(jù)庫

本篇文章為大家展示了MongoDB從入坑到入迷的過程是怎樣的,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

背景:我司是一家正處于高速發(fā)展,目前擁有數(shù)百萬用戶,年銷售額近五十億的社交電商公司。公司技術(shù)部建立之初,為了適應(yīng)用戶量的高速增長,與業(yè)務(wù)的不斷變更迭代,在選用數(shù)據(jù)庫的時候,經(jīng)過調(diào)研對比我們選擇了MongoDB。

是的,你沒看錯,All in MongoDB!

1.為什么使用MongoDB

因為我司主要做社交電商的業(yè)務(wù),所以對數(shù)據(jù)庫的性能有一定的要求,加上商品交易是公司主要盈利來源,所以對數(shù)據(jù)庫的高可用也有一定的要求。

總結(jié)一下我們對數(shù)據(jù)庫的要求:

  • 安全,穩(wěn)定

  • 高可用

  • 高性能

我們在考慮數(shù)據(jù)庫選型的時候主要考慮什么?

  • 數(shù)據(jù)規(guī)模

  • 支持讀寫并發(fā)量

  • 延遲與吞吐量

從數(shù)據(jù)規(guī)模來說訂單和商品SKU,還有會員信息這些重要的數(shù)據(jù)記錄肯定會隨著時間源源不斷的增長,所以我們需要的不僅僅是滿足當(dāng)下要求,更需要為半年一年后海量數(shù)據(jù)更為方便的擴容做考量!

下面我們從MongoDB的架構(gòu),性能,和文檔模型來介紹一下我們選擇MongoDB的理由!

2.MongoDB架構(gòu)

2.1 關(guān)于高可用

數(shù)據(jù)庫作為系統(tǒng)核心,要保證99.99%的可用性,而高可用的保證來自于MongoDB冗余數(shù)據(jù)的復(fù)制集模式。MongoDB自帶多副本高可用,只需要合理的配置,就能避免單數(shù)據(jù)庫節(jié)點故障導(dǎo)致服務(wù)的不可用。

MongoDB從入坑到入迷的過程是怎樣的

圖例說明:

  • 一個Primary主節(jié)點,主要接受來自server的讀寫;

  • 兩個Secondary從節(jié)點,用于同步來自Primary的數(shù)據(jù)。

關(guān)于高可用:當(dāng)主節(jié)點發(fā)生故障的時候,兩個從節(jié)點會進行選舉,投票產(chǎn)生一個新的主節(jié)點,進而保證服務(wù)的可用性。(PS:在選舉過程中數(shù)據(jù)不可寫入,但是如果Secnondary節(jié)點配置可讀,那么此時是可以讀取數(shù)據(jù)的。)這就是MongoDB的高可用,配置簡單,不需要引入額外的中間件或者插件去輔助數(shù)據(jù)庫節(jié)點間的故障轉(zhuǎn)移。

2.2 關(guān)于選舉算法《分布式一致性算法---raft》

raft協(xié)議是在leader節(jié)點發(fā)生故障或者網(wǎng)絡(luò)分區(qū)導(dǎo)致腦裂時如何保證分布式數(shù)據(jù)一致性的一個算法,MongoDB采用了該算法來保證當(dāng)主節(jié)點故障或者網(wǎng)絡(luò)分區(qū)的情況下,數(shù)據(jù)的一致性。當(dāng)然MongoDB用的和raft原版算法肯定會略有不同,MongoDB會采用Secondary向Primary拉數(shù)據(jù),而不是Primary向Secondary推數(shù)據(jù)的方式來減輕Primary的壓力等等有利于數(shù)據(jù)庫操作的方式對raft進行改進使用。

raft算法動畫演示

http://thesecretlivesofdata.com/raft/

2.3 關(guān)于超大規(guī)模復(fù)制集(集群)

MongoDB從入坑到入迷的過程是怎樣的

{    "_id" : <num>,    "host" : <hostname:port>,    "arbiterOnly" : false,    "buildIndexes" : true,    "hidden" : false,    "priority" : 0,  // 設(shè)置為0    "tags" : {      },    "slaveDelay" : NumberLong(0),    "votes" : 0  // 設(shè)置為0 }

MongoDB最多允許50個節(jié)點,但是最多只有7個節(jié)點有投票權(quán),一個節(jié)點可以配置7個無投票權(quán)的Non-Voting節(jié)點,加上一個Primary節(jié)點。

為什么只能允許存在7個投票節(jié)點呢?參考2.2小節(jié)的raft算法,節(jié)點越多,投票時間越長,選舉出來的Primary節(jié)點時間也就越長,這個過程中我們是無法進行寫操作的,因為沒有主節(jié)點。

那么多非投票節(jié)點有什么用呢?大家應(yīng)該都聽過MySQL的讀寫分離吧,利用讀寫分離來提高數(shù)據(jù)庫性能。  MongoDB這里其實也可以,Primary用來寫,Secondary用來讀,可以給BI部門一個Secondary,給財務(wù)部門一個Secondary,給運營部門一個Secondary&middot;&middot;&middot;&middot;&middot;&middot;

2.4 WriteConcern

既然我們的數(shù)據(jù)庫擁有至少超過三個節(jié)點(1Primary+2Secondary),Secondary通過同步Primary的數(shù)據(jù)來保持一致性,那么當(dāng)我們寫操作的時候,如何保證數(shù)據(jù)安全的落盤呢?

MongoDB從入坑到入迷的過程是怎樣的

有以下幾種情況:

1. 寫Primary成功,返回客戶端寫成功,Secondary還未同步Primary的時候,Primary掛了,數(shù)據(jù)丟失!

2.  寫Primary成功,數(shù)據(jù)同步一個Secondary成功,返回客戶端寫成功。此時Primary掛了,數(shù)據(jù)不會丟失。但是恰好Primary與同步的Secondary同時掛了,數(shù)據(jù)丟失!

3. 寫Primary成功,數(shù)據(jù)同步兩個Secondary成功,返回客戶端寫成功。此時Primary掛了,數(shù)據(jù)不會丟失。

我們對以上三種情況進行分析:第一種情況有風(fēng)險會造成數(shù)據(jù)丟失。第二種情況還是會出現(xiàn)數(shù)據(jù)丟失,但是數(shù)據(jù)丟失的概率大大降低。第三種情況是最安全的做法,但是節(jié)點數(shù)目多了,同步非常耗時,用戶需要等待的時間過長,一般不考慮。

MongoDB在這里推薦折衷方案就是使用Write Concern---在數(shù)據(jù)可靠性與效率之間的權(quán)衡!

db.products.insert(    { item: "envelopes", qty : 100, type: "Clasp" },    { writeConcern: { w: "majority" , wtimeout: 5000 } }  // 設(shè)置writeConcern為majority,超時時間為5000毫秒 )

3.MongoDB分片

3.1 大規(guī)模數(shù)據(jù)是如何影響數(shù)據(jù)庫效率的?

數(shù)據(jù)庫的性能還與數(shù)據(jù)庫本身規(guī)模息息相關(guān)。拿關(guān)系型數(shù)據(jù)庫舉例:

  • 查詢百萬表和千萬表甚至過億的表效率相差很大,查詢性能急劇惡化。

  • 插入的時候創(chuàng)建索引可能會引起索引樹的調(diào)整與頁分裂。

3.2 面對海量數(shù)據(jù)如何提升數(shù)據(jù)讀寫效率?

為了在海量數(shù)據(jù)中提升數(shù)據(jù)庫的效率,我們采用分而治之的思想,將大表拆成小表,大庫拆成小庫。

關(guān)系型數(shù)據(jù)庫中我們常用分表分庫來解決:

  • 例如將訂單庫分為在線庫和離線庫,近三個月是在線庫,遠期的訂單數(shù)據(jù)放入離線庫,這樣在線庫的數(shù)據(jù)就大大減少,數(shù)據(jù)庫性能就得到了提升。

  • 又例如當(dāng)我們的用戶量過多超過千萬行記錄,單表查詢效率下降,我們將一張用戶表拆成多張用戶表,這個就是水平拆分。

MongoDB中我們是如何做的呢?

3.3 MongoDBSharding

MongoDB從入坑到入迷的過程是怎樣的

MongoDB的分片

通過將同一個集合(Collection1)的數(shù)據(jù)按片鍵(shard  keys)分到不同的分片(shard)上面,減少同一個數(shù)據(jù)文件上的數(shù)據(jù)量,已達到拆分?jǐn)?shù)據(jù)規(guī)模的目的。

MongoDB從入坑到入迷的過程是怎樣的

Shard 優(yōu)勢:在線擴容,動態(tài)擴容

Shard:用于存儲實際的數(shù)據(jù)塊,實際生產(chǎn)環(huán)境中一個shard server角色可由幾臺機器組個一個replica set承擔(dān),防止主機單點故障。

Config Server:配置服務(wù)器 mongod實例,存儲了整個集群的元數(shù)據(jù)與配置,其中包括 chunk信息,在MongoDB  3.4中,配置服務(wù)器必須部署為一個副本集。

Mongos:mongos充當(dāng)查詢路由器,提供客戶端應(yīng)用程序和切分集群之間的接口。

服務(wù)器插入的數(shù)據(jù)通過Mongos路由到具體地址,這也是MongoDB的便利之處,不需要自己關(guān)注路由,也不需要使用第三方提供的中間件輔助路由,可靠,放心。

MongoDB從入坑到入迷的過程是怎樣的

分片的負(fù)載均衡

當(dāng)我們的MongoDB 副本集變成分片集群后,隨著數(shù)據(jù)量的增長,各個分片也會越來越大,這里就會出現(xiàn)兩種情況:

1. 冷熱數(shù)據(jù),某個分片數(shù)據(jù)量過大。

2. 數(shù)據(jù)總量大,分片集群的分片過大。

當(dāng)出現(xiàn)問題(1)的時候,MongoDB的負(fù)載均衡器(Balancer)會自動將大分片中的數(shù)據(jù)遷往小分片。注意這并不意味我們可以高枕無憂了,恰恰相反,我們應(yīng)該反思是不是自己片鍵選擇失誤而造成的數(shù)據(jù)不均勻!因為對分片遷移也是消耗性能的,應(yīng)用服務(wù)器寫一次到Shard  B,然后Shard B重寫到Shard C無形之中數(shù)據(jù)被寫了兩次,這是極大的浪費!

當(dāng)出現(xiàn)問題(2)的時候,當(dāng)然是給過大的分片集合添加新的分片以此分?jǐn)偡制旱膲毫Α?/p>

注意:MongoDB分片雖然是可在線的,但是多少都會對正常的讀寫操作性能有一定的影響,建議在非繁忙時間段進行分片部署!

4.MongoDB文檔模型介紹

數(shù)據(jù)庫建模的挑戰(zhàn)在于平衡應(yīng)用的需要,適合該數(shù)據(jù)庫引擎發(fā)揮的結(jié)構(gòu)以及數(shù)據(jù)的檢索模式。當(dāng)我們設(shè)計數(shù)據(jù)模型的時候,需要考慮應(yīng)用使用數(shù)據(jù)的情況(查詢,更新,和數(shù)據(jù)處理)以及該數(shù)據(jù)本身的結(jié)構(gòu)。

4.1 靈活的Schema

在關(guān)系型數(shù)據(jù)庫中,必須按照確定的表結(jié)構(gòu)去插入數(shù)據(jù)。但是,由于MongoDB是文檔型數(shù)據(jù)庫,在插入數(shù)據(jù)的時候默認(rèn)并不對此做要求。其表現(xiàn)在于:

同一個集合中不同文檔不一定需要有相同的字段,并且字段類型也可以不同。

在集合中改變文檔的結(jié)構(gòu),例如增加一個字段,刪除一個字段,或者改變一個字段的類型,只需要對該文檔更新即可。

4.2 舉例1:N模型設(shè)計

在電商業(yè)務(wù)中,一個用戶可能有多個收件人以及收件地址。在關(guān)系型數(shù)據(jù)庫中,我們需要建立聯(lián)系人表,地址表,并且將其關(guān)聯(lián)。但是在MongoDB中,我們只需要一個集合就能將此搞定!

數(shù)據(jù)關(guān)系如下:

// patron document {    _id: "joe",    name: "Joe Bookreader" }   // address documents {    patron_id: "joe", // reference to patron document    street: "123 Fake Street",    city: "Faketon",    state: "MA",    zip: "12345" }   {    patron_id: "joe",    street: "1 Some Other Street",    city: "Boston",    state: "MA",    zip: "12345" }

在MongoDB中我們可以這樣進行設(shè)計:

{    "_id": "joe",    "name": "Joe Bookreader",    "addresses": [                 {                   "street": "123 Fake Street",                   "city": "Faketon",                   "state": "MA",                   "zip": "12345"                 },                 {                   "street": "1 Some Other Street",                   "city": "Boston",                   "state": "MA",                   "zip": "12345"                 }               ]  }

沒錯,以上就是集合中的一個document(文檔),是不是感覺很靈活很方便!你可以在SKU集合中添加分類信息,或者商品標(biāo)簽,還可以在庫存集合中冗余SKU的基本信息,還可以在訂單集合中冗余部分下單者信息&middot;&middot;&middot;沒錯,就是這么靈活!這也是我們選擇MongoDB的一個重要原因之一,讓開發(fā)者的心智負(fù)擔(dān)少了很多,不需要成為SQL高手,你也能在MongoDB中寫出性能優(yōu)異的查詢語句。

當(dāng)然冗余一時爽,重構(gòu)火葬場的段子也不是沒聽過,因為過多的冗余最終會造成數(shù)據(jù)的過于臃腫,性能降低等各種問題,這個要控制住開發(fā)者的冗余沖動,也依賴于團隊技術(shù)Leader對此的把關(guān)。

互聯(lián)網(wǎng)業(yè)務(wù)不是一成不變的,產(chǎn)品和用戶的需求還有市場都一直在變!我們沒有技術(shù)實力打造一個能夠適應(yīng)靈活多變的業(yè)務(wù)的中臺,但是目前我們可以選擇一個可靠,強大并且靈活的數(shù)據(jù)庫  -- MongoDB!

上述內(nèi)容就是MongoDB從入坑到入迷的過程是怎樣的,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI