Jen

Mongo DB Sharding 心得筆記 (一)

自從 小賴 被公司操到爆肝的事件發生之後,一氣之下,自已一個人跑去開公司,開始做案子賺大錢,一個人自由自在,做起事來得心應手,過得非常開心。但好景不常,公司的業務越來越多,多到他一個人開始負荷不了,這時,他找來了 黃Teyou,平均分配工作量,按表操課,讓每個人的效益達到最佳化,使得公司能夠運作的更順利,而這種分配工作量的概念,就是 Sharding。

以下就是我讀 Scaling MongoDB 這本書的的心得筆記。

瞭解 Mongo DB 的 Sharding
要在網路上找到架設 Mongo DB Sharding 的方式很容易,範例也很多,但如果你沒有去瞭解運作原理的話,當你的資料量一大起來,或者 Shard 一多,就會變得難以管理,發生了一點問題要除錯的時候,你更可能不知道要從何下手。所以一定要來瞭解 Mongo DB Sharding 的運作原理,而這篇文章會介紹以下四個主題:

  1. 資料切割 : 告訴你 Sharding 之間的資料怎麼做切割
  2. Balancing:怎麼 平均 分配
  3. mongos (route server) : 提供單一連線介面給 Client 
  4. Config Server: 用來儲存每個 Shard 之間的狀態

1.資料切割
Cluster 會有許多個 Shard,而每個 Shard 包含總資料的子集合。以上圖為例子,整個 Cluster 的資料量是 400GB,這個Cluster有 4 個 Shard,每個Shard 各有 100 GB 的資料,每個 Shard 由1組ReplSet 組成,每一個 ReplSet 由 3 個 Mongod 組成,而這 3 個 Mongod 因為 replication 機制都擁有相同的資料。那400GB的資料是用什麼規則來分配哪些 100GB 給 Shard A ,另外哪些 100GB 給 Shard B 呢? 
Mongo DB 可以指定一個欄位的值當作 Key ,作為切割資料的依據,而這個 Key,我們稱為 Shard Key,可以是一個欄位或多個欄位。書上有提到 2 種切割方式:

第一種切割方式:One range per shard 
假設我們的會員資料有個欄位是 age,Cluster 有 4 shard,我們會這樣分配我們的資料:
Shard A : [0,25)
Shard B : [25,50)
Shard C : [50,75)
Shard D : [75,100)
註:[ , ] : inclusive bounds (大於、小於) 、 ( , ) : exclusive bounds (超過、不及)
意思就是說 年齡不到 25 歲的會員資料將會被分配到 Shard A,25 ~ 49 歲的會員資料會被分配到 Shard B,以此類推。這是最直覺的資料切割方式,平均給定切割範圍。
但問題來了, 你確定 75歲以上的會員數會跟 25~50歲的會員數一樣多嗎? 如果你的 Application 是做養老院會員管理系統,我想50歲以下的會員數會是 0 吧,所以這會造成每個 Shard 的大小難以平均,而當每個 Shard 的大小不平均的時候, Mongo DB 會開始把較大的 shard 切割,然後分配給較小的 Shard,如下圖:
(此圖節錄自 Scaling MongoDB,作者:Kristina Chodorow)

而當你新增一個節點的時候,
(此圖節錄自 Scaling MongoDB,作者:Kristina Chodorow)

這樣過程中,會產生許多資料移動的成本,要盡可能的讓這行為發生的次數降低。

第二種:Multi range per shard
這種切割方式是不預先給定範圍,當資料量成長到一個程度的時候才開始切割,然後分配給其他比較資料量比較小的 Shard,而這個切割出來的東西稱作「 Chunk 」。
同樣以有 age 的會員資料表來做例子,一開始 chunk 的 range 為  (-∞,∞) ,也就是所有資料都會進到 第一個 Shard ,當資料量達到一定大小的時候,假設是 200 MB,Mongo DB 就會開始切割資料,可能會由 (-∞,∞) 變成 (-∞ , 50]  跟  (50,∞) ,然後分配資料到 Chunk 最少的Shard 。

【注意事項】
  • Chunk 可以只有一個值來當作切割範圍,例如:姓氏。
  • Chunk 之間不能重疊,而且必需相連,例如: [1,3),[3,6),[6,9)....
  • 每個文件只能屬於1個 Chunk。
  • Shard Key 可以是 Null ,但新增資料的時候一定要帶 Shard Key 欄位。
  • 無法更改 Shard Key, 除非刪除資料,更改 Shard key 之後,重新 insert。
  • Shard Key 可以為多型態欄位,排序的規則:null > numbers > strings > objects > arrays > binary data > ObjectIds > booleans > dates > regular expressions
  • 200 MB 大小的 Chunk 是最佳選擇。

2.Balancing
做資料的切割、移動、合併就稱作 Balancing,而做這些事的就稱作 Balancer。它的工作除了保持各 Shards 之間資料量的平衡之外,最重要的就是降低 Balancing 的次數,減少 Chunk 在各 Shard 之間的傳輸量。

有一種比較 tricky 的情況,當 Shard A 比 Shard B 多 2 個 Chunks 的時候,就會開始 Balancing,從 Shard A 移動 1 個 Chunk 到 Shard B ,讓 2 個 Shard 之間保持相同的 Chunk 數量,合理,沒錯。
但天算不如人算,接下來的資料剛好都被分配到 Shard B,造成 Shard B 又比 Shard A 多 2 個 Chunks,然後 MongDB 再從 Shard B 移動 1 個 Chunk 到 Shard A。
哇哩咧,移來移去不就裝肖仔。事實上 Mongo DB 是不會這麼容易移動 Chunk ,當最多 Chunk 數的 Shard 比最少 Chunk 數的 Shard 多 9 個 Chunk,Mongo DB 才會開始幫你做 Balancing 移動、合併資料的動作。
而在開發階段,可以用 --chunkSize 自訂 Chunk 大小來看看 Balancing 的效果,但 Production 就不要再亂改了。

3.Mongos( Route Server)
Mongos 提供一個介面給 User 來使用,讓 User 覺得使用 Cluster 跟使用 Single Node 一樣簡單。
新增:
當你在新增資料的時候,他會去分析 Shard Key ,然後把這筆資料送到該去的 Shard 去儲存。
查詢
而當你使用 Shard Key 做查詢的時候,一樣只會把這個查詢送到相對應的 Shrad 做查詢,這樣查詢稱為「targeted query」;那如果沒有包含 Shard Key , Mongos 會把這個 Query 送往每一個 Shrad ,等回應之後再合併結果,稱為「spewed query」。通常 targeted query 的效率會比 spewed query 來的好。


4.Config Server
用來儲存所有 Shards 的狀態,如果要讓 Chunk 在各 Shard 之間確實的做到切割及合併,就要仰賴 Config Server。如果在合併的過程中, Config Server 掛掉,所有的正在執行的合併都會中斷,然後回到合併前的狀態,而所有儲存在 Config Server 的狀態將會被凍住,不能被改變,一直到 Config Server 重啟

整個 Mongo DB Sharding 的架構就像是下面這張圖。



小賴跟 Teyou 從此過著快樂的生活 !?

1 意見:

  匿名

2013年1月30日 下午1:46

太简单了。