MongoDB 走馬觀花(全面解讀篇)

一铐拐、簡介

MongoDB 是一款流行的開源文檔型數(shù)據(jù)庫,從它的命名來看练对,確實(shí)是有一定野心的遍蟋。
MongoDB 的原名一開始來自于 英文單詞"Humongous", 中文含義是指"龐大",即命名者的意圖是可以處理大規(guī)模的數(shù)據(jù)螟凭。

但筆者更喜歡稱呼它為 "芒果"數(shù)據(jù)庫虚青,除了譯音更加相近之外,原因還來自于這幾年使用 MongoDB 的兩層感覺:

  • 第一層感受是"爽"螺男,使用這個(gè)文檔數(shù)據(jù)庫的特點(diǎn)是幾乎不受什么限制棒厘,一方面Json文檔式的結(jié)構(gòu)更容易理解,而無Schema約束也讓DDL管理更加簡單下隧,一切都可以很快速的進(jìn)行绊谭。

  • 第二層感受是"酸爽",這點(diǎn)相信干運(yùn)維或是支撐性工作的兄弟感受會(huì)比較深刻汪拥,MongoDB 由于入門體驗(yàn)"太過于友好"达传,導(dǎo)致一些團(tuán)隊(duì)認(rèn)為用好這個(gè)數(shù)據(jù)庫是個(gè)很簡單的事情,所以開發(fā)兄弟在存量系統(tǒng)上埋一些坑也是正常的事情迫筑。
    所謂交付一時(shí)爽宪赶,維護(hù)火葬場.. 當(dāng)然了,這句話可能有些過脯燃。 但這里的潛臺(tái)詞是:與傳統(tǒng)的RDBMS數(shù)據(jù)庫一樣搂妻,MongoDB 在使用上也需要認(rèn)真的考量和看護(hù),不然的化辕棚,會(huì)遇到更多的坑欲主。

那么邓厕,盡管文檔數(shù)據(jù)庫在選型上會(huì)讓一些團(tuán)隊(duì)望而卻步,仍然不阻礙該數(shù)據(jù)庫所獲得的一些支持扁瓢,比如 DB-Engine 上的排名:

圖-DBEngine排名

在全部的排名中详恼,MongoDB 長期排在第5位(文檔數(shù)據(jù)庫排名第1位),同時(shí)也是最受歡迎的 NoSQL 數(shù)據(jù)庫引几。
另外昧互,MongoDB 的社區(qū)一直比較活躍,加上商業(yè)上的驅(qū)動(dòng)(MongoDB于2017年在納斯達(dá)克上市)伟桅,這些因素都推動(dòng)了該開源數(shù)據(jù)庫的發(fā)展敞掘。

如果對(duì)于 MongoDB的發(fā)展史感興趣,可以參考下沒有一個(gè)技術(shù)天生完美楣铁,MongoDB 十年發(fā)展全紀(jì)錄這篇文章玖雁。

MongoDB 數(shù)據(jù)庫的一些特性:

  • 面向文檔存儲(chǔ),基于JSON/BSON 可表示靈活的數(shù)據(jù)結(jié)構(gòu)
  • 動(dòng)態(tài) DDL能力盖腕,沒有強(qiáng)Schema約束茄菊,支持快速迭代
  • 高性能計(jì)算,提供基于內(nèi)存的快速數(shù)據(jù)查詢
  • 容易擴(kuò)展赊堪,利用數(shù)據(jù)分片可以支持海量數(shù)據(jù)存儲(chǔ)
  • 豐富的功能集面殖,支持二級(jí)索引、強(qiáng)大的聚合管道功能哭廉,為開發(fā)者量身定做的功能脊僚,如數(shù)據(jù)自動(dòng)老化、固定集合等等遵绰。
  • 跨平臺(tái)版本辽幌、支持多語言SDK..

假定你是初次了解 MongoDB,下面的內(nèi)容將能幫助你對(duì)該數(shù)據(jù)庫技術(shù)的全貌產(chǎn)生一定的了解椿访。

二乌企、基本模型

數(shù)據(jù)結(jié)構(gòu)對(duì)于一個(gè)軟件來說是至關(guān)重要的,MongoDB 在概念模型上參考了 SQL數(shù)據(jù)庫成玫,但并非完全相同加酵。

關(guān)于這點(diǎn),也有人說哭当,MongoDB 是 NoSQL中最像SQL的數(shù)據(jù)庫..

如下表所示:

SQL概念 MongoDB概念
database database
table collection
row document
column field
  • database 數(shù)據(jù)庫猪腕,與SQL的數(shù)據(jù)庫(database)概念相同,一個(gè)數(shù)據(jù)庫包含多個(gè)集合(表)
  • collection 集合钦勘,相當(dāng)于SQL中的表(table)陋葡,一個(gè)集合可以存放多個(gè)文檔(行)。 不同之處就在于集合的結(jié)構(gòu)(schema)是動(dòng)態(tài)的彻采,不需要預(yù)先聲明一個(gè)嚴(yán)格的表結(jié)構(gòu)腐缤。更重要的是捌归,默認(rèn)情況下 MongoDB 并不會(huì)對(duì)寫入的數(shù)據(jù)做任何schema的校驗(yàn)。
  • document 文檔岭粤,相當(dāng)于SQL中的行(row)惜索,一個(gè)文檔由多個(gè)字段(列)組成,并采用bson(json)格式表示绍在。
  • field 字段门扇,相當(dāng)于SQL中的列(column)雹有,相比普通column的差別在于field的類型可以更加靈活偿渡,比如支持嵌套的文檔、數(shù)組霸奕。
    此外溜宽,MongoDB中字段的類型是固定的、區(qū)分大小寫质帅、并且文檔中的字段也是有序的适揉。

另外,SQL 還有一些其他的概念煤惩,對(duì)應(yīng)關(guān)系如下:

SQL概念 MongoDB概念
primary key _id
foreign key reference
view view
index index
join $lookup
transaction trasaction
group by aggregation
  • _id 主鍵嫉嘀,MongoDB 默認(rèn)使用一個(gè)_id 字段來保證文檔的唯一性。
  • reference 引用魄揉,勉強(qiáng)可以對(duì)應(yīng)于 外鍵(foreign key) 的概念剪侮,之所以是勉強(qiáng)是因?yàn)?reference 并沒有實(shí)現(xiàn)任何外鍵的約束,而只是由客戶端(driver)自動(dòng)進(jìn)行關(guān)聯(lián)查詢洛退、轉(zhuǎn)換的一個(gè)特殊類型瓣俯。
  • view 視圖,MongoDB 3.4 開始支持視圖兵怯,和 SQL 的視圖沒有什么差異彩匕,視圖是基于表/集合之上進(jìn)行動(dòng)態(tài)查詢的一層對(duì)象,可以是虛擬的媒区,也可以是物理的(物化視圖)驼仪。
  • index 索引,與SQL 的索引相同袜漩。
  • $lookup谅畅,這是一個(gè)聚合操作符,可以用于實(shí)現(xiàn)類似 SQL-join 連接的功能
  • transaction 事務(wù)噪服,從 MongoDB 4.0 版本開始毡泻,提供了對(duì)于事務(wù)的支持
  • aggregation 聚合,MongoDB 提供了強(qiáng)大的聚合計(jì)算框架粘优,group by 是其中的一類聚合操作仇味。

BSON 數(shù)據(jù)類型

MongoDB 文檔可以使用 Javascript 對(duì)象表示呻顽,從格式上講,是基于 JSON 的丹墨。

一個(gè)典型的文檔如下:

{
  "_id": 1,
  "name" : { "first" : "John", "last" : "Backus" },
  "contribs" : [ "Fortran", "ALGOL", "Backus-Naur Form", "FP" ],
  "awards" : [
    {
      "award" : "W.W. McDowell Award",
      "year" : 1967,
      "by" : "IEEE Computer Society"
    }, {
      "award" : "Draper Prize",
      "year" : 1993,
      "by" : "National Academy of Engineering"
    }
  ]
}

曾經(jīng)廊遍,JSON 的出現(xiàn)及流行讓 Web 2.0 的數(shù)據(jù)傳輸變得非常簡單,所以使用 JSON 語法是非常容易讓開發(fā)者接受的贩挣。
但是 JSON 也有自己的短板喉前,比如無法支持像日期這樣的特定數(shù)據(jù)類型,因此 MongoDB 實(shí)際上使用的是一種擴(kuò)展式的JSON王财,叫 BSON(Binary JSON)卵迂。

BSON 所支持的數(shù)據(jù)類型包括:

image

圖-BSON類型

分布式ID

在單機(jī)時(shí)代,大多數(shù)應(yīng)用可以使用數(shù)據(jù)庫自增式ID 來作為主鍵绒净。 傳統(tǒng)的 RDBMS 也都支持這種方式见咒,比如 mysql 可以通過聲明 auto_increment來實(shí)現(xiàn)自增的主鍵。 但一旦數(shù)據(jù)實(shí)現(xiàn)了分布式存儲(chǔ)挂疆,這種方式就不再適用了改览,原因就在于無法保證多個(gè)節(jié)點(diǎn)上的主鍵不出現(xiàn)重復(fù)。

為了實(shí)現(xiàn)分布式數(shù)據(jù)ID的唯一性保證缤言,應(yīng)用開發(fā)者提出了自己的方案庆揩,而大多數(shù)方案中都會(huì)將ID分段生成腾仅,如著名的 snowflake 算法中就同時(shí)使用了時(shí)間戳验辞、機(jī)器號(hào)壳贪、進(jìn)程號(hào)以及隨機(jī)數(shù)來保證唯一性磕蒲。

MongoDB 采用 ObjectId 來表示主鍵的類型秆乳,數(shù)據(jù)庫中每個(gè)文檔都擁有一個(gè)_id 字段表示主鍵。
_id 的生成規(guī)則如下:

圖-ObjecteID

其中包括:

  • 4-byte Unix 時(shí)間戳
  • 3-byte 機(jī)器 ID
  • 2-byte 進(jìn)程 ID
  • 3-byte 計(jì)數(shù)器(初始化隨機(jī))

值得一提的是 _id 的生成實(shí)質(zhì)上是由客戶端(Driver)生成的伦乔,這樣可以獲得更好的隨機(jī)性,同時(shí)降低服務(wù)端的負(fù)載哑舒。
當(dāng)然服務(wù)端也會(huì)檢測寫入的文檔是否包含_id 字段瞪浸,如果沒有就生成一個(gè)。

三刚操、操作語法

除了文檔模型本身菊霜,對(duì)于數(shù)據(jù)的操作命令也是基于JSON/BSON 格式的語法。

比如插入文檔的操作:

db.book.insert(
{
  title: "My first blog post",
  published: new Date(),
  tags: [ "NoSQL", "MongoDB" ],
  type: "Work",
  author : "James",
  viewCount: 25,
  commentCount: 2
}
)

執(zhí)行文檔查找:

db.book.find({author : "James"})

更新文檔的命令:

db.book.update(
   {"_id" : ObjectId("5c61301c15338f68639e6802")},
   {"$inc": {"viewCount": 3} }
)

刪除文檔的命令:

db.book.remove({"_id":
     ObjectId("5c612b2f15338f68639e67d5")})

在傳統(tǒng)的SQL語法中济赎,可以限定返回的字段鉴逞,MongoDB可以使用Projection來表示:

db.book.find({"author": "James"}, 
    {"_id": 1, "title": 1, "author": 1})

實(shí)現(xiàn)簡單的分頁查詢:

db.book.find({})
    .sort({"viewCount" : -1})
    .skip(10).limit(5)

這種基于BSON/JSON 的語法格式并不復(fù)雜,它的表達(dá)能力或許要比SQL更加強(qiáng)大司训。
與 MongoDB 做法類似的還有 ElasticSearch构捡,后者是搜索數(shù)據(jù)庫的佼佼者。

關(guān)于文檔操作與 SQL方式完整的對(duì)比壳猜,官方的文檔描述得比較詳細(xì):
https://docs.mongodb.com/manual/reference/sql-comparison/

那么勾徽,一個(gè)有趣的問題是 MongoDB 能不能用 SQL進(jìn)行查詢?

當(dāng)然是可以蓖谢!

但需要注意這些功能并不是 MongoDB 原生自帶的捂蕴,而需要借由第三方工具平臺(tái)實(shí)現(xiàn):

  • 客戶端使用SQL,可以使用 mongobooster闪幽、studio3t 這樣的工具
  • 服務(wù)端的話啥辨,可以看看 presto 之類的一些平臺(tái)..

四、索引

無疑盯腌,索引是一個(gè)數(shù)據(jù)庫的關(guān)鍵能力溉知,MongoDB 支持非常豐富的索引類型。
利用這些索引,可以實(shí)現(xiàn)快速的數(shù)據(jù)查找级乍,而索引的類型和特性則是針對(duì)不同的應(yīng)用場景設(shè)計(jì)的舌劳。

索引的技術(shù)實(shí)現(xiàn)依賴于底層的存儲(chǔ)引擎,在當(dāng)前的版本中 MongoDB 使用 wiredTiger 作為默認(rèn)的引擎玫荣。
在索引的實(shí)現(xiàn)上使用了 B+樹的結(jié)構(gòu)甚淡,這與其他的傳統(tǒng)數(shù)據(jù)庫并沒有什么不同。
所以這是個(gè)好消息捅厂,大部分基于SQL數(shù)據(jù)庫的一些索引調(diào)優(yōu)技巧在 MongoDB 上仍然是可行的贯卦。

image

圖-B+樹

使用 ensureIndexes 可以為集合聲明一個(gè)普通的索引:

db.book.ensureIndex({author: 1})

author后面的數(shù)字 1 代表升序,如果是降序則是 -1

實(shí)現(xiàn)復(fù)合式(compound)的索引焙贷,如下:

db.book.ensureIndex({type: 1, published: 1})

只有對(duì)于復(fù)合式索引時(shí)撵割,索引鍵的順序才變得有意義

如果索引的字段是數(shù)組類型,該索引就自動(dòng)成為數(shù)組(multikey)索引:

db.book.ensureIndex({tags: 1})

MongoDB 可以在復(fù)合索引上包含數(shù)組的字段辙芍,但最多只能包含一個(gè)

索引特性

在聲明索引時(shí)啡彬,還可以通過一些參數(shù)化選項(xiàng)來為索引賦予一定的特性,包括:

  • unique=true故硅,表示一個(gè)唯一性索引
  • expireAfterSeconds=3600庶灿,表示這是一個(gè)TTL索引,并且數(shù)據(jù)將在1小時(shí)后老化
  • sparse=true契吉,表示稀疏的索引跳仿,僅索引非空(non-null)字段的文檔
  • partialFilterExpression: { rating: { $gt: 5 }诡渴,條件式索引捐晶,即滿足計(jì)算條件的文檔才進(jìn)行索引

索引分類

除了普通索引之外,MongoDB 支持的類型還包括:

  • 哈希(HASH)索引妄辩,哈希是另一種快速檢索的數(shù)據(jù)結(jié)構(gòu)惑灵,MongoDB 的 HASH 類型分片鍵會(huì)使用哈希索引。
  • 地理空間索引眼耀,用于支持快速的地理空間查詢英支,如尋找附近1公里的商家。
  • 文本索引哮伟,用于支持快速的全文檢索
  • 模糊索引(Wildcard Index)干花,一種基于匹配規(guī)則的靈活式索引,在4.2版本開始引入楞黄。

索引評(píng)估池凄、調(diào)優(yōu)

使用 explain() 命令可以用于查詢計(jì)劃分析,進(jìn)一步評(píng)估索引的效果鬼廓。
如下:

> db.test.explain().find( { a : 5 } )

{
  "queryPlanner" : {
    ...
    "winningPlan" : {
      "stage" : "FETCH",
      "inputStage" : {
        "stage" : "IXSCAN",
        "keyPattern" : {
            "a" : 5
        },
        "indexName" : "a_1",
        "isMultiKey" : false,
        "direction" : "forward",
        "indexBounds" : {"a" : ["[5.0, 5.0]"]}
        }
    }},
   ...
}

從結(jié)果 winningPlan 中可以看出執(zhí)行計(jì)劃是否高效肿仑,比如:

  • 未能命中索引的結(jié)果,會(huì)顯示COLLSCAN
  • 命中索引的結(jié)果,使用IXSCAN
  • 出現(xiàn)了內(nèi)存排序尤慰,顯示為 SORT

關(guān)于 explain 的結(jié)果說明馏锡,可以進(jìn)一步參考文檔:

https://docs.mongodb.com/manual/reference/explain-results/index.html

五、集群

在大數(shù)據(jù)領(lǐng)域常常提到的4V特征中伟端,Volume(數(shù)據(jù)量大)是首當(dāng)其沖被提及的杯道。
由于單機(jī)垂直擴(kuò)展能力的局限,水平擴(kuò)展的方式則顯得更加的靠譜责蝠。 MongoDB 自帶了這種能力蕉饼,可以將數(shù)據(jù)存儲(chǔ)到多個(gè)機(jī)器上以提供更大的容量和負(fù)載能力。
此外玛歌,同時(shí)為了保證數(shù)據(jù)的高可用昧港,MongoDB 采用副本集的方式來實(shí)現(xiàn)數(shù)據(jù)復(fù)制。

一個(gè)典型的MongoDB集群架構(gòu)會(huì)同時(shí)采用分片+副本集的方式支子,如下圖:

image

圖-MongoDB 分片集群(Shard Cluster)

架構(gòu)說明

  • 數(shù)據(jù)分片(Shards)
    分片用于存儲(chǔ)真正的集群數(shù)據(jù)创肥,可以是一個(gè)單獨(dú)的 Mongod實(shí)例,也可以是一個(gè)副本集值朋。 生產(chǎn)環(huán)境下Shard一般是一個(gè) Replica Set叹侄,以防止該數(shù)據(jù)片的單點(diǎn)故障。
    對(duì)于分片集合(sharded collection)來說昨登,每個(gè)分片上都存儲(chǔ)了集合的一部分?jǐn)?shù)據(jù)(按照分片鍵切分)趾代,如果集合沒有分片,那么該集合的數(shù)據(jù)都存儲(chǔ)在數(shù)據(jù)庫的 Primary Shard中丰辣。

  • 配置服務(wù)器(Config Servers)
    保存集群的元數(shù)據(jù)(metadata)撒强,包含各個(gè)Shard的路由規(guī)則,配置服務(wù)器由一個(gè)副本集(ReplicaSet)組成笙什。

  • 查詢路由(Query Routers)
    Mongos是 Sharded Cluster 的訪問入口飘哨,其本身并不持久化數(shù)據(jù) 。Mongos啟動(dòng)后琐凭,會(huì)從 Config Server 加載元數(shù)據(jù)芽隆,開始提供服務(wù),并將用戶的請求正確路由到對(duì)應(yīng)的Shard统屈。
    Sharding 集群可以部署多個(gè) Mongos 以分擔(dān)客戶端請求的壓力胚吁。

分片機(jī)制

下面的幾個(gè)細(xì)節(jié),對(duì)于理解和應(yīng)用 MongoDB 的分片機(jī)制比較重要愁憔,所以有必要提及一下:

1. 數(shù)據(jù)如何切分

首先腕扶,基于分片切分后的數(shù)據(jù)塊稱為 chunk,一個(gè)分片后的集合會(huì)包含多個(gè) chunk惩淳,每個(gè) chunk 位于哪個(gè)分片(Shard) 則記錄在 Config Server(配置服務(wù)器)上蕉毯。
Mongos 在操作分片集合時(shí)乓搬,會(huì)自動(dòng)根據(jù)分片鍵找到對(duì)應(yīng)的 chunk,并向該 chunk 所在的分片發(fā)起操作請求代虾。

數(shù)據(jù)是根據(jù)分片策略來進(jìn)行切分的进肯,而分片策略則由 分片鍵(ShardKey)+分片算法(ShardStrategy)組成。

MongoDB 支持兩種分片算法:

  • 范圍分片

如上圖所示棉磨,假設(shè)集合根據(jù)x字段來分片江掩,x的取值范圍為[minKey, maxKey](x為整型,這里的minKey乘瓤、maxKey為整型的最小值和最大值)环形,將整個(gè)取值范圍劃分為多個(gè)chunk,每個(gè)chunk(默認(rèn)配置為64MB)包含其中一小段的數(shù)據(jù):
如Chunk1包含x的取值在[minKey, -75)的所有文檔衙傀,而Chunk2包含x取值在[-75, 25)之間的所有文檔...

范圍分片能很好的滿足范圍查詢的需求抬吟,比如想查詢x的值在[-30, 10]之間的所有文檔,這時(shí) Mongos 直接能將請求路由到 Chunk2统抬,就能查詢出所有符合條件的文檔火本。 范圍分片的缺點(diǎn)在于,如果 ShardKey 有明顯遞增(或者遞減)趨勢聪建,則新插入的文檔多會(huì)分布到同一個(gè)chunk钙畔,無法擴(kuò)展寫的能力,比如使用_id作為 ShardKey金麸,而MongoDB自動(dòng)生成的id高位是時(shí)間戳擎析,是持續(xù)遞增的。

  • 哈希分片

Hash分片是根據(jù)用戶的 ShardKey 先計(jì)算出hash值(64bit整型)挥下,再根據(jù)hash值按照范圍分片的策略將文檔分布到不同的 chunk揍魂。
由于 hash值的計(jì)算是隨機(jī)的,因此 Hash 分片具有很好的離散性见秽,可以將數(shù)據(jù)隨機(jī)分發(fā)到不同的 chunk 上愉烙。 Hash 分片可以充分的擴(kuò)展寫能力,彌補(bǔ)了范圍分片的不足解取,但不能高效的服務(wù)范圍查詢,所有的范圍查詢要查詢多個(gè) chunk 才能找出滿足條件的文檔返顺。

2. 如何保證均衡

如前面的說明中禀苦,數(shù)據(jù)是分布在不同的 chunk上的,而 chunk 則會(huì)分配到不同的分片上遂鹊,那么如何保證分片上的 數(shù)據(jù)(chunk) 是均衡的呢振乏?
在真實(shí)的場景中,會(huì)存在下面兩種情況:

  • A. 全預(yù)分配秉扑,chunk 的數(shù)量和 shard 都是預(yù)先定義好的慧邮,比如 10個(gè)shard调限,存儲(chǔ)1000個(gè)chunk,那么每個(gè)shard 分別擁有100個(gè)chunk误澳。
    此時(shí)集群已經(jīng)是均衡的狀態(tài)(這里假定)

  • B. 非預(yù)分配耻矮,這種情況則比較復(fù)雜,一般當(dāng)一個(gè) chunk 太大時(shí)會(huì)產(chǎn)生分裂(split)忆谓,不斷分裂的結(jié)果會(huì)導(dǎo)致不均衡裆装;或者動(dòng)態(tài)擴(kuò)容增加分片時(shí),也會(huì)出現(xiàn)不均衡的狀態(tài)倡缠。 這種不均衡的狀態(tài)由集群均衡器進(jìn)行檢測哨免,一旦發(fā)現(xiàn)了不均衡則執(zhí)行 chunk數(shù)據(jù)的搬遷達(dá)到均衡。

MongoDB 的數(shù)據(jù)均衡器運(yùn)行于 Primary Config Server(配置服務(wù)器的主節(jié)點(diǎn))上昙沦,而該節(jié)點(diǎn)也同時(shí)會(huì)控制 Chunk 數(shù)據(jù)的搬遷流程琢唾。

image

圖-數(shù)據(jù)自動(dòng)均衡

對(duì)于數(shù)據(jù)的不均衡是根據(jù)兩個(gè)分片上的 Chunk 個(gè)數(shù)差異來判定的,閾值對(duì)應(yīng)表如下:

Number of Chunks Migration Threshold
Fewer than 20 2
20-79 4
80 and greater 8

MongoDB 的數(shù)據(jù)遷移對(duì)集群性能存在一定影響盾饮,這點(diǎn)無法避免慧耍,目前的規(guī)避手段只能是將均衡窗口對(duì)齊到業(yè)務(wù)閑時(shí)段。

3. 應(yīng)用高可用

應(yīng)用節(jié)點(diǎn)可以通過同時(shí)連接多個(gè) Mongos 來實(shí)現(xiàn)高可用丐谋,如下:

image

圖- mongos 高可用

當(dāng)然芍碧,連接高可用的功能是由 Driver 實(shí)現(xiàn)的。

副本集

副本集又是另一個(gè)話題号俐,實(shí)質(zhì)上除了前面架構(gòu)圖所體現(xiàn)的攘残,副本集可以作為 Shard Cluster 中的一個(gè)Shard(片)之外,對(duì)于規(guī)模較小的業(yè)務(wù)來說议谷,也可以使用一個(gè)單副本集的方式進(jìn)行部署笆怠。
MongoDB 的副本集采取了一主多從的結(jié)構(gòu),即一個(gè)Primary Node + N* Secondary Node的方式猪落,數(shù)據(jù)從主節(jié)點(diǎn)寫入贞远,并復(fù)制到多個(gè)備節(jié)點(diǎn)。

典型的架構(gòu)如下:

利用副本集笨忌,我們可以實(shí)現(xiàn)::

  • 數(shù)據(jù)庫高可用蓝仲,主節(jié)點(diǎn)宕機(jī)后,由備節(jié)點(diǎn)自動(dòng)選舉成為新的主節(jié)點(diǎn)官疲;
  • 讀寫分離袱结,讀請求可以分流到備節(jié)點(diǎn),減輕主節(jié)點(diǎn)的單點(diǎn)壓力途凫。

請注意垢夹,讀寫分離只能增加集群"讀"的能力,對(duì)于寫負(fù)載非常高的情況卻無能為力维费。
對(duì)此需求果元,使用分片集群并增加分片促王,或者提升數(shù)據(jù)庫節(jié)點(diǎn)的磁盤IO、CPU能力可以取得一定效果而晒。

選舉

MongoDB 副本集通過 Raft 算法來完成主節(jié)點(diǎn)的選舉蝇狼,這個(gè)環(huán)節(jié)在初始化的時(shí)候會(huì)自動(dòng)完成,如下面的命令:

config = {
    _id : "my_replica_set",
    members : [
        {_id : 0, host : "rs1.example.net:27017"},
        {_id : 1, host : "rs2.example.net:27017"},
        {_id : 2, host : "rs3.example.net:27017"},
  ]
}
rs.initiate(config)

initiate 命令用于實(shí)現(xiàn)副本集的初始化欣硼,在選舉完成后题翰,通過 isMaster()命令就可以看到選舉的結(jié)果:

> db.isMaster()

{
    "hosts" : [
    "192.168.100.1:27030",
    "192.168.100.2:27030",
    "192.168.100.3:27030"
    ],
    "setName" : "myReplSet",
    "setVersion" : 1,
    "ismaster" : true,
    "secondary" : false,
    "primary" : "192.168.100.1:27030",
    "me" : "192.168.100.1:27030",
    "electionId" : ObjectId("7fffffff0000000000000001"),
    "ok" : 1
}

受 Raft算法的影響,主節(jié)點(diǎn)的選舉需要滿足"大多數(shù)"原則诈胜,可以參考下表:

投票成員數(shù) 大多數(shù)
1 1
2 2
3 2
4 3
5 3

因此豹障,為了避免出現(xiàn)平票的情況,副本集的部署一般采用是基數(shù)個(gè)節(jié)點(diǎn)焦匈,比如3個(gè)血公,正所謂三人行必有我?guī)?.

心跳

在高可用的實(shí)現(xiàn)機(jī)制中,心跳(heartbeat)是非常關(guān)鍵的缓熟,判斷一個(gè)節(jié)點(diǎn)是否宕機(jī)就取決于這個(gè)節(jié)點(diǎn)的心跳是否還是正常的累魔。
副本集中的每個(gè)節(jié)點(diǎn)上都會(huì)定時(shí)向其他節(jié)點(diǎn)發(fā)送心跳,以此來感知其他節(jié)點(diǎn)的變化够滑,比如是否失效垦写、或者角色發(fā)生了變化。
利用心跳彰触,MongoDB 副本集實(shí)現(xiàn)了自動(dòng)故障轉(zhuǎn)移的功能梯投,如下圖:

image

默認(rèn)情況下,節(jié)點(diǎn)會(huì)每2秒向其他節(jié)點(diǎn)發(fā)出心跳况毅,這其中包括了主節(jié)點(diǎn)分蓖。 如果備節(jié)點(diǎn)在10秒內(nèi)沒有收到主節(jié)點(diǎn)的響應(yīng)就會(huì)主動(dòng)發(fā)起選舉。
此時(shí)新一輪選舉開始尔许,新的主節(jié)點(diǎn)會(huì)產(chǎn)生并接管原來主節(jié)點(diǎn)的業(yè)務(wù)么鹤。 整個(gè)過程對(duì)于上層是透明的,應(yīng)用并不需要感知味廊,因?yàn)?Mongos 會(huì)自動(dòng)發(fā)現(xiàn)這些變化蒸甜。
如果應(yīng)用僅僅使用了單個(gè)副本集,那么就會(huì)由 Driver 層來自動(dòng)完成處理毡们。

復(fù)制

主節(jié)點(diǎn)和備節(jié)點(diǎn)的數(shù)據(jù)是通過日志(oplog)復(fù)制來實(shí)現(xiàn)的迅皇,這很類似于 mysql 的 binlog。
在每一個(gè)副本集的節(jié)點(diǎn)中衙熔,都會(huì)存在一個(gè)名為local.oplog.rs的特殊集合。 當(dāng) Primary 上的寫操作完成后搅荞,會(huì)向該集合中寫入一條oplog红氯,
而 Secondary 則持續(xù)從 Primary 拉取新的 oplog 并在本地進(jìn)行回放以達(dá)到同步的目的框咙。

下面,看看一條 oplog 的具體形式:

{
"ts" : Timestamp(1446011584, 2),
"h" : NumberLong("1687359108795812092"),
"v" : 2,
"op" : "i",
"ns" : "test.nosql",
"o" : { "_id" : ObjectId("563062c0b085733f34ab4129"), "name" : "mongodb", "score" : "100" }
}

其中的一些關(guān)鍵字段有:

  • ts 操作的 optime痢甘,該字段不僅僅包含了操作的時(shí)間戳(timestamp)喇嘱,還包含一個(gè)自增的計(jì)數(shù)器值。
  • h 操作的全局唯一表示
  • v oplog 的版本信息
  • op 操作類型塞栅,比如 i=insert,u=update..
  • ns 操作集合者铜,形式為 database.collection
  • o 指具體的操作內(nèi)容,對(duì)于一個(gè) insert 操作放椰,則包含了整個(gè)文檔的內(nèi)容

MongoDB 對(duì)于 oplog 的設(shè)計(jì)是比較仔細(xì)的作烟,比如:

  • oplog 必須保證有序,通過 optime 來保證砾医。
  • oplog 必須包含能夠進(jìn)行數(shù)據(jù)回放的完整信息拿撩。
  • oplog 必須是冪等的,即多次回放同一條日志產(chǎn)生的結(jié)果相同如蚜。
  • oplog 集合是固定大小的压恒,為了避免對(duì)空間占用太大,舊的 oplog 記錄會(huì)被滾動(dòng)式的清理错邦。

有興趣的讀者探赫,可以參考官方文檔:

https://docs.mongodb.com/manual/core/replica-set-oplog/index.html

六、事務(wù)與一致性

一直以來撬呢,"不支持事務(wù)" 是 MongoDB 一直被詬病的問題伦吠,當(dāng)然也可以說這是 NoSQL 數(shù)據(jù)庫的一種權(quán)衡(放棄事務(wù),追求高性能倾芝、高可擴(kuò)展)
但實(shí)質(zhì)上讨勤,MongoDB 很早就有事務(wù)的概念,但是這個(gè)事務(wù)只能是針對(duì)單文檔的晨另,即單個(gè)文檔的操作是有原子性保證的潭千。
在4.0 版本之后,MongoDB 開始支持多文檔的事務(wù):

  • 4.0 版本支持副本集范圍的多文檔事務(wù)借尿。
  • 4.2 版本支持跨分片的多文檔事務(wù)(基于兩階段提交)刨晴。

在事務(wù)的隔離性上,MongoDB 支持快照(snapshot)的隔離級(jí)別路翻,可以避免臟讀狈癞、不可重復(fù)讀和幻讀。
盡管有了真正意義上的事務(wù)功能茂契,但多文檔事務(wù)對(duì)于性能有一定的影響蝶桶,應(yīng)用應(yīng)該在充分評(píng)估后再做選用。

一致性

一致性是一個(gè)復(fù)雜的話題掉冶,而一致性更多從應(yīng)用角度上提出的真竖,比如:

向系統(tǒng)寫入一條數(shù)據(jù)脐雪,應(yīng)該能夠馬上讀到寫入的這個(gè)數(shù)據(jù)。

在分布式架構(gòu)的CAP理論以及許多延續(xù)的觀點(diǎn)中提到恢共,由于網(wǎng)絡(luò)分區(qū)的存在战秋,要求系統(tǒng)在一致性和可用性之間做出選擇,而不能兩者兼得讨韭。

圖 -CAP理論

在 MongoDB 中脂信,這個(gè)選擇是可以由開發(fā)者來定的。 MongoDB 允許客戶端為其操作設(shè)定一定的級(jí)別或者偏好透硝,包括:

  • read preference
    讀取偏好狰闪,可指定讀主節(jié)點(diǎn)、讀備節(jié)點(diǎn)蹬铺,或者是優(yōu)先讀主尝哆、優(yōu)先讀備、取最近的節(jié)點(diǎn)
  • write concern
    寫關(guān)注甜攀,指定寫入結(jié)果達(dá)到什么狀態(tài)時(shí)才返回秋泄,可以為無應(yīng)答(none)、應(yīng)答(ack)规阀,或者是大多數(shù)節(jié)點(diǎn)完成了數(shù)據(jù)復(fù)制等等
  • read concern
    讀關(guān)注恒序,指定讀取的數(shù)據(jù)版本處于怎樣的狀態(tài),可以為讀本地谁撼、讀大多數(shù)節(jié)點(diǎn)寫入歧胁,或者是線性讀(linearizable)等等。

使用不同的設(shè)定將會(huì)產(chǎn)生對(duì)于C(一致性)厉碟、A(可用性)的不同的抉擇喊巍,比如:

  • 將讀偏好設(shè)置為 primary,此時(shí)讀寫都在主節(jié)點(diǎn)上箍鼓。 這保證了數(shù)據(jù)的一致性崭参,但一旦主節(jié)點(diǎn)宕機(jī)會(huì)導(dǎo)致失敗(可用性降低)
  • 將讀偏好設(shè)置為 secondaryPrefered,此時(shí)寫主款咖,優(yōu)先讀備何暮,可用性提高了,但數(shù)據(jù)存在延遲(出現(xiàn)不一致)
  • 將讀寫關(guān)注都設(shè)置為 majority(大多數(shù))铐殃,一致性提升了海洼,但可用性也同時(shí)降低了(節(jié)點(diǎn)失效會(huì)導(dǎo)致大多數(shù)寫失敗)

關(guān)于這種權(quán)衡的討論會(huì)一直存在,而 MongoDB 除了提供多樣化的選擇之外富腊,其主要是通過復(fù)制坏逢、基于心跳的自動(dòng)failover等機(jī)制來降低系統(tǒng)發(fā)生故障時(shí)產(chǎn)生的影響,從而提升整體的可用性。

小結(jié)

本文主要揭示了 MongoDB 多個(gè)方面的細(xì)節(jié)词疼,同時(shí)在使用體驗(yàn)上也借助 SQL 的概念做了一些對(duì)比俯树。
從筆者的角度看帘腹,MongoDB 的發(fā)展性是很強(qiáng)的贰盗,其靈活快速的開發(fā)模式、天生自帶分布式等能力彌補(bǔ)了傳統(tǒng)型SQL數(shù)據(jù)庫的缺陷阳欲。當(dāng)然舵盈,目前的 NewSQL 本質(zhì)上也貌似在以"模仿的方式"彌補(bǔ)這些缺陷。

希望本文的內(nèi)容對(duì)你能有些參考球化。

轉(zhuǎn)載于 https://www.cnblogs.com/littleatp/p/11675233.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秽晚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子筒愚,更是在濱河造成了極大的恐慌赴蝇,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巢掺,死亡現(xiàn)場離奇詭異句伶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)陆淀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門考余,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人轧苫,你說我怎么就攤上這事楚堤。” “怎么了含懊?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵身冬,是天一觀的道長。 經(jīng)常有香客問我岔乔,道長酥筝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任重罪,我火速辦了婚禮樱哼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘剿配。我一直安慰自己搅幅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布呼胚。 她就那樣靜靜地躺著茄唐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沪编,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天呼盆,我揣著相機(jī)與錄音,去河邊找鬼蚁廓。 笑死访圃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的相嵌。 我是一名探鬼主播腿时,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼饭宾!你這毒婦竟也來了批糟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤看铆,失蹤者是張志新(化名)和其女友劉穎徽鼎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弹惦,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡否淤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肤频。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叹括。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宵荒,靈堂內(nèi)的尸體忽然破棺而出汁雷,到底是詐尸還是另有隱情,我是刑警寧澤报咳,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布侠讯,位于F島的核電站,受9級(jí)特大地震影響暑刃,放射性物質(zhì)發(fā)生泄漏厢漩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一岩臣、第九天 我趴在偏房一處隱蔽的房頂上張望溜嗜。 院中可真熱鬧,春花似錦架谎、人聲如沸炸宵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽土全。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間裹匙,已是汗流浹背瑞凑。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留概页,地道東北人籽御。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像绰沥,于是被迫代替她去往敵國和親篱蝇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 復(fù)制集 mongodb在集群環(huán)境中徽曲,通過復(fù)制的形式對(duì)數(shù)據(jù)進(jìn)行冗余。mongodb復(fù)制集有Primary麸塞、Secon...
    奕_然閱讀 1,973評(píng)論 0 2
  • NoSql數(shù)據(jù)庫優(yōu)缺點(diǎn) 在優(yōu)勢方面主要體現(xiàn)在下面幾點(diǎn): 簡單的擴(kuò)展 快速的讀寫 低廉的成本 靈活的數(shù)據(jù)模型 在不足...
    dreamer_lk閱讀 2,730評(píng)論 0 6
  • 第一章:邏輯結(jié)構(gòu) 選擇之所以稱之為選擇,肯定是痛苦的!------->oldguo 第二章:安裝部署 1秃臣、系統(tǒng)準(zhǔn)備...
    王亞飛1992閱讀 748評(píng)論 0 0
  • 第一章:邏輯結(jié)構(gòu) 第二章:安裝部署 1、系統(tǒng)準(zhǔn)備 2哪工、mongodb安裝 創(chuàng)建所需用戶和組 創(chuàng)建mongodb所需...
    zwb_jianshu閱讀 1,600評(píng)論 0 1
  • 1.1 MongoDB復(fù)制集簡介 一組Mongodb復(fù)制集奥此,就是一組mongod進(jìn)程,這些進(jìn)程維護(hù)同一個(gè)數(shù)據(jù)集合雁比。...
    IT_小白閱讀 821評(píng)論 0 4