Johannes Brandstettercs目前是omSysto GmbH開發運營總監,曾擔任1&1 IT經理;致力於MongoDB、Hadoop、AWS上的項目研究。
縱觀最領先的應用程式建模和基礎設施最佳實現的設計,很容易的發現一個問題:如果需要性能的快速增長並適應從0到千萬請求的自由縮放,只有一條路可走 —— 橫向擴展(Scale Out)!
擴展通常是描述給系統添加更多資源的方法。需要從兩個方面區別:
縱向擴展(Scale vertically/up)
縱向擴展意味著給系統中單個節點增加資源,代表性的添加有單計算機的CPU或者內存提升。
橫向擴展(Scale horizontally/out)
橫向擴展意味著增加系統中節點的數目,比如說給一個分布式軟體應用程式中添加計算機。舉個簡單的例子,將Web伺服器系統中的伺服器從1個提升到3個。
使用MongoDB,你可以根據你的需求從兩個方面去擴展:專注讀操作或是寫操作的提升。
10gen告訴了我們一些擴展選項:
「自帶橫向擴展能力,MongoDB允許用戶快速的建立和提高他們的應用程式。通過自動分片,你可以輕鬆的將數據分配到不同的節點上。副本集提供高可靠性,跨數據中心實現節點故障自動轉移和恢復。」
聽起來不錯,事實上呢?現在開始著手把2400萬條數據導入由6個節點組成的MongoDB集群,這裡使用的是自動分片:
從上圖看結果並不是很好,呈現出很不均勻的寫入性能。假專注於單個節點的性能,情況比上面看起來更加的糟糕:
分別點擊查看大圖
這裡不僅要看到所有節點上不均勻的寫入速度,還要看到節點間每秒寫入操作的巨大差別。有一瞬間Node2達到 4000 insert/s的,而那個時刻node5隻有 740 insert/s !
為什麼會這樣?我們使用mongoimport監視了整個導入過程發現:開始的一段時間內一切運行的很好,我們的集群也提供了一個很好的吞吐量;但是隨著時間的推移,速度在逐漸的減緩。而通過mongostat,我們不難發現:有時候幾秒內許多節點並沒有分配到任何數據。
想了解原因,我們必須要看一下MongoDB的分片機制。這裡不得不看一下3個基本組件:
1. MongoDB Sharding Router(mongos)
所有通往集群的連接都由mongos選擇,分片對應用層來說是完全透明的 —— 通過Transparent Query Routing進行路由。
2. Mongo Config Server
決定元數據中某個部分該分配到哪個對應的節點上。
3. Mongo Shard Node
用來支撐數據的普通mongod進程。
那麼要把數據儲存到這樣的集群中,你必須去做元數據查詢來核對當前的數據該寫到哪個節點上。然而即使每次寫入前去決定目標節點會產生一定的開銷,這裡的性能損失也不該來的如此之大。
但是現實就是這麼殘酷!這裡要提起的就是Mongo Config Server,也就是必須要告訴MongoDB哪個範圍的數據需要被用來分片。這就是傳說中的「shard key」!同樣如果你在shard key上做了個錯誤的決定,將會引起一系列的麻煩。當然為了簡潔明了,這裡選擇一個我們認為很適合我們數據類型的shard key。
那麼MongoDB現在做的就是在內部把數據放入所謂的「chunk」 —— 很像固定大小的data bucket。這樣一來每個chunk中都包含了一定範圍的數據並且只是一定容量的數據(默認64MB)。當我們把數據導入資料庫,這些chunk將會被注入數據,一旦數據裝滿就會被MongoDB分割。這樣一來必定會發生下面兩種情況:
現在我們就有必要關注一下第二點了!因為我們並沒有告訴MongoDB任何shard key相關或者是怎麼分布的,MongoDB在分片前則必須進行最好的預估然後嘗試將數據平均的分配到分片中。它通過在任何給定時間內保持所有節點上chunk數量相同這一策略來保障數據的平均分配。在MongoDB 2.2中,新遷移閾值被引進並成功的將平衡集群帶來的影響降到最低。然而Mongo同樣不知道shard key的範圍和分布,那麼就很可能發生熱點區域 —— 很大一部分的數據被寫入了同一個分片,因此也只在同一個節點上。
既然我們知道了問題的所在,我們是否能夠做點什麼?
數據預分割
想做數據預分割必須對你將要導入的數據有充分的認識,所以取代讓MongoDB完成chunk的選擇你需要親自動手。取決於你shard key的選擇,你既可以使用一個腳本生成相關的命令(一個不錯的用例)也可以使用MongoDB文檔提供的方法。無論如何你都將完成對MongoDB chunk分配位置的告知:
當然你還可以強制MongoDB給chunk分配相應的節點。同樣這取決於你的用例及應用程式對數據的讀取方式。這裡需要注意的是保留數據的局部性。
增加chunk大小
文檔中有具體的chunk大小說明:
1. 小的chunk以頻繁遷移為代價獲取數據更均勻的分布,這樣會給Query Routing Layer增加更多的開銷。
2. 大的chunk會顯著的減少遷移,不管是從網絡設計還是從內部Query Routing Layer開銷上都會帶來收益。當然這些收益是以潛在的數據分布不均為代價。
而為了能讓MongoDB能運行的足夠快,這裡把chunk的大小提升為1GB。當然這是建立在對自己數據的了解上,所以務必讓chunk的大小來的更有價值。
關閉Balancer
既然我們已經給chunk指定了具體節點,並且不希望在這過程中有新chunk的建立;我們可以使用以下的命令來關閉Balancer:
1.
2.
選擇正確的shard key
Shard key是節點分布的核心。詳情點擊這裡獲得shard key相關的建議。在MongoDB 2.4中還支持MongoDB自主選擇哈希shard key的選項。
通過這些努力,導入情況如下:
上圖為集群中一個節點上的速率。當然還是有一些縫隙,因為數據不是絕對均與的進入。但總的來這是一個很大的提升,整個集群上的導入速度達到每秒4608次插入;現在導入速度只受到節點間網絡接口的限制。
總結
天下沒有免費的午餐!想獲得卓越的性能,就必須親力親為。
原文連結:Scaling MongoDB – Know your Sharding Kung Fu (編譯/仲浩 王旭東/審校)
歡迎關注@CSDN雲計算微博,了解更多雲信息。
本文為CSDN編譯整理,未經允許不得轉載。如需轉載請聯繫market@csdn.net