MongoDB实战-分片概念和原理
1. 什么是分片 ? ??
? ? ? 到目前為止,你都是把MongoDB當做一臺服務器在用,每個mongod實例都包含應用程序數據的完整副本。就算使用了復制,每個副本也都是完整克隆了其他副本的數據。對于大多數應用程序而言,在一臺服務器上保存完整數據集是完全可以接受的。但隨著數據量的增長,以及應用程序對讀寫吞吐量的要求越來越高,普通服務器漸漸顯得捉襟見肘了。尤其是這些服務器可能無法分配足夠的內存,或者沒有足夠的CPU核數來有效處理工作負荷。除此之外,隨著數據量的增長,要在一塊磁盤或者一組RAID陣列上保存和管理備份如此大規模的數據集也變得不太現實。如果還想繼續使用普通硬件或者虛擬硬件來托管數據庫,那么這對這類問題的解決方案就是將數據庫分布到多臺服務器上,這種方法稱之為分片。
? ? 為數眾多的Web應用程序,知名的如Flicker和LiveJournal,都實現了手動分片,將負載分布到多臺MySQL數據庫上。在這些實現中,分片邏輯都寄生于應用程序上。要明白這是如何實現的,想象一下,假如你有很多用戶,需要將Users表分布到多臺數據庫服務器上。你可以指定一臺數據庫作為元數據庫。這臺數據庫包含每個用戶ID(或者用戶ID范圍)到指定分片映射關系的元數據。因此,要查詢一個用戶實際涉及兩次查詢:第一次查詢訪問元數據庫以獲得用戶的分片位置,第二次查詢直接訪問包含用戶數據的分片。
? ? 對于這些Web應用程序而言,手動分片解決了負載問題,但氣質并非無懈可擊。最明顯的問題就是遷移數據非常困難。如果單個分片負載過重,將其中的數據遷移到其他分片的過程完全是手動的。手動分片的第二個問題在于編寫可靠的應用程序代碼對于讀寫請求進行路由,并且將數據庫作為一個整體進行管理,這也是非常困難的。最近也出現了管理手動分片的的框架,最著名的就是Twitter的Gizzard。
? ? 但正如那些手動分片數據庫的人所說,要把事情做好并非易事。MongoDB中有一大塊工作就是為了解決這個問題。因為分片是MongoDB的核心內容,所以用戶無需擔心在需求水平擴展時要自己設計外置分片框架。在處理困難的跨分片數據均衡問題時,這點尤為重要。這些代碼并非那些大多數人在一個周末能夠寫出來的東西。
? ? 也許最值得一提的是MongoDB在設計時為應用程序提供了統一接口,無論是在分片前,還是在分片后。也就是說,在數據庫需要轉換為分片架構時,應用程序幾乎無需改變。
2. 何時分片
? ? 這個問題的答案比你想的簡單得多。我們之前已經說過把索引和工作數據集放在內存里時很重要的,這也是分片的主要原因。如果應用程序的數據集持續無限增長,那么遲早一天,內存會容納不下這些數據。如果你正在使用亞馬遜的EC2,那么這個閾值是68GB。或者你可以運行自己的硬件,并使用遠高于68GB的內存,這樣便能延后一段時間再做分片。但沒有哪臺機器內存時無限的,因此你早晚都會用到分片。
? ? 不可否認,還有一些其他的應對措施。舉例來說,如果你有自己的硬件,而且可以將所有的數據都保存在固態硬盤上,那么可以增加數據內存比,而不會為性能帶來負面影響。還有一種情況,工作集是總數據量中的一部分,這是可以使用相對較小的內存。另一方面,如果有特殊的寫負載要求,那么可以在數據達到內存大小之前先進行適當的分片,原因是需要將負載分到多臺機器上,以便能夠獲得想要的吞吐量。
? ? 無論哪種情況,對現有系統進行分片的決定都要基于以下幾點--磁盤活動、系統負載以及最重要的工作集大小與可用內存的比例。
3. 分片的工作原理
? ? 要理解分片是如何工作的,你需要了解構成分片集群的組件,理解協調哪些組件的軟件進程。
(1)分片組件
? ?分片集群由分片、mongos路由器和配置服務器組成。如下圖所示
分片
MongoDB分片集群將數據分布在一個或多個分片上。每個分片部署成一個MongoDB副本集,該副本集保存了集群整體數據的一部分。因為每個分片都是一個副本集,所以他們擁有自己的復制機制,能夠自動進行故障轉移。你可以直接連接單個分片,就像連接單獨的副本集一樣。但是,如果連接的副本集是分片集群的一部分,那么只能看到部分數據。
mongos路由器
? ? ? 如果每個分片都包含部分集群數據,那么還需要一個接口連接整個集群。這就是mongos。mongos進程是一個路由器,將所有的讀寫請求指引到合適的分片上。如此一來,mongos為客戶端提供了一個合理的系統視圖。
? ? ?mongos進程是輕量級且非持久化的。它們通常運行與與應用服務器相同的機器上,確保對任意分片的請求只經過一次網絡跳轉。換言之,應用程序連接本地的mongos,而mongos管理了指向單獨分片的連接。
配置服務器
? ? 如果mongs進程是非持久化的,那么必須有地方能持久保存集群的公認狀態;這就是配置服務器的工作,其中持久化了分片集群的元數據,改數據包括:每個數據庫,集合和特定范圍數據的位置;一份變更記錄,保存了數據在分片之間進行遷移的歷史信息。配置服務器中保存的元數據是某些特定功能和集群維護是的重中之重。舉例來說,每次有mongos進程啟動,它都會從配置服務器中獲取一份元數據的副本。沒有這些數據,就無法獲得一致的分片集群視圖。該數據的重要性對配置服務器的設計和部署也有影響。
? ?如上面結構圖中所示,有三個配置服務器,但它們并不是以副本集的形式部署的。它們比異步復制要求更嚴格;mongos進程向配置服務器寫入時,會使用兩階段提交。這能保證配置服務器之間的一致性。在各種生產環境的分片部署中,必須運行三個配置服務器,這些服務器都必須部署在獨立的機器上以實現冗余。
(2) 核心分片操作
? ? ?MongoDB分片集群在兩個級別上分布數據。較粗的是以數據庫為粒度的,在集群里新建數據庫時,每個數據庫都會被分配到不同的分片里。如果不進行別的設置,數據庫以及其中的集合永遠都會在創建它的分片里。 因為大多數的應用程序都會把所有的數據保存在一個數據庫里,因此這種分布方式帶來的幫助不大。你需要更細粒度的分布方式,集合的粒度剛好能夠滿足要求。MongoDB的分片是專門為了將單獨的集合分布在多個分片里而設計的。
? ? 假設你正在構建一套基于云的辦公軟件,用于管理電子表格,并且要求將所有的數據都保存在MongoDB里。用戶可以隨心所欲地創建大量文檔,每個文檔都會保存為單獨的MongoDB文檔,放在一個spreadsheets集合里。隨著時間的流逝,假設你的應用程序發展到了擁有100萬用戶。現在再想想那兩個主要集合:users和spreadsheets。users集合還比較容易處理,就算有100萬用戶,每個用戶文檔1KB,整個集合大概也就1GB,一臺機器就搞定了。但spreadsheets集合就大不一樣了,假設每個用戶平均擁有50張電子表格,平均大小是50KB,那么我們所談論的就是1TB的spreadsheets集合。要是這個應用程序的活躍度很高,你會希望將數據放在內存里,要將數據放在內存里并且分布讀寫負載,就必須將集合分片。
? ?分片一個集合
? ?MongoDB的分片是基于范圍的。也就是說分片集合里的每個文檔都必須落在指定鍵的某個值范圍里。MongoDB使用所謂的分片鍵(shard key)讓每個文檔在這些范圍里找到自己的位置。(其他的分布式數據庫里可能使用分區鍵partition key或分布鍵 distribution key來代替分片鍵這個術語)從假想的電子表格管理應用程序里拿出一個實例文檔,這樣能更好地理解分片鍵:
{ _id:ObjectId("4d6e9b89b600c2c196442c21") filename:"spreadsheet-1" updated_at:ISODate("2017-09-04T19:22:54.845z") username:"banks" data:"raw documnet data" }? ? 在對該集合進行分片時,必須將其中的一個或多個字段申明為分片鍵。如果選擇_id,那么文檔會基于對象ID的范圍進行分布。但是,處于一些原因,你要基于username和_id聲明一個復合分片鍵:因此,這些范圍通常會表示Wie一系列用戶名? ?現在你需要理解塊(chunk)的概念,它是位于一個分片中的一段連續的分片鍵范圍。舉例來說,可以假設docs集合分布在兩個分片A和B上,它被分成下表所示的多個塊。每個塊的范圍都由起始值和終止值來標識。
| 起始值 | 終止值 | 分片 |
| -無窮大 | abbot | B |
| abbot | dayton | A |
| dayton | harris | B |
| harris | norris | A |
| norris | 無窮大 | B |
? ? ? 拆分與遷移
? ? ?分片機制的重點是塊的拆分(spliting)與遷移(migration)
? ? ? 首先,考慮一下塊拆分的思想。在初始化分片集群時,只存在一個塊,這個塊的范圍涵蓋了整個分片集合。那該如何發展到有多個塊的分片集群呢?答案就是塊大小達到某個閾值是就會對塊進行拆分。默認的塊的最大塊尺寸時64MB或者100000個文檔,先達到哪個標準就以哪個標準為準。在向新的分片集群添加數據時,原始的塊最終會達到某個閾值,觸發塊的拆分。這是一個簡單的操作,基本就是把原來的范圍一分為二,這樣就有兩個塊,每個塊都有相同數量的文檔。
? ? ?請注意,塊的拆分是個邏輯操作。當MongoDB進行塊拆分時,它只是修改塊的元數據就能讓一個塊變為兩個。因此,拆分一個塊并不影響分片集合里文檔的物理順序。也就是說拆分既簡單又快捷。
? ? ?你可以回想一下,設計分片系統時最大的一個困難就是保證數據始終均勻分布。MongoDB的分片集群是通過在分片中移動塊來實現均衡的。我們稱之為遷移,這是一個真實的物理操作。
? ? 遷移是由名為均衡器(balancer)的軟件進程管理的,它的任務就是確保數據在各個分片中保持均勻變化。通過追蹤各分片上塊的數量,就能實現這個功能。雖然均衡的觸發會隨總數據量的不同而變化,但是通常來說,當集群中擁有塊最多的分片與擁有塊最少的分片的塊數相差大于8時,均衡器就會發起一次均衡處理。在均衡過程中,塊會從塊較多的分片遷移到塊較少非分片上,直到兩個分片的塊數大致相等為止。
總結
以上是生活随笔為你收集整理的MongoDB实战-分片概念和原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: R语言实战(第二版)第七章-基本统计分析
- 下一篇: 软考 | 2017年上半年 软件设计师