1. 程式人生 > 實用技巧 >MongoDB分片(Sharding)技術

MongoDB分片(Sharding)技術

MongoDB分片介紹

分片(sharding)是MongoDB用來將大型集合分割到不同伺服器(或者說一個叢集)上所採用的方法。儘管分片起源於關係型資料庫分割槽,但MongoDB分片完全又是另一回事。

和MySQL分割槽方案相比,MongoDB的最大區別在於它幾乎能自動完成所有事情,只要告訴MongoDB要分配資料,它就能自動維護資料在不同伺服器之間的均衡

分片的目的

高資料量和吞吐量的資料庫應用會對單機的效能造成較大壓力,大的查詢量會將單機的CPU耗盡,大的資料量對單機的儲存壓力較大,最終會耗盡系統的記憶體而將壓力轉移到磁碟IO上。

為了解決這些問題,有兩個基本的方法: 垂直擴充套件和水平擴充套件。

 垂直擴充套件:增加更多的CPU和儲存資源來擴充套件容量。

 水平擴充套件:將資料集分佈在多個伺服器上。水平擴充套件即分片。

分片設計思想

分片為應對高吞吐量與大資料量提供了方法。使用分片減少了每個分片需要處理的請求數,因此,通過水平擴充套件,叢集可以提高自己的儲存容量和吞吐量。舉例來說,當插入一條資料時,應用只需要訪問儲存這條資料的分片.

使用分片減少了每個分片儲存的資料。

  例如,如果資料庫1tb的資料集,並有4個分片,然後每個分片可能僅持有256 GB的資料。如果有40個分片,那麼每個切分可能只有25GB的資料。

分片機制提供瞭如下三種優勢

1.mongos對叢集進行抽象,讓叢集“不可見”

  mongodb中沒有failover機制,官方建議是將mongos和應用伺服器部署在一起,多個應用伺服器就要部署多個mongos例項。mongos作為統一路口的路由器,其會將客戶端發來的請求準確無誤的路由到叢集中的一個或者一組伺服器上,同時會把接收到的響應拼裝起來發回到客戶端。

mongos的高可用可以用有幾種方法可以使這三個mongos介面都利用起來,減少單個介面的壓力。常用的有LVS和HAProxy。於是嘗試用HAProxy做負載均衡。

mongodb可以以單複製集的方式執行,client 直連 mongod 讀取資料。

單複製集的方式下,資料的水平擴充套件的責任推給了業務層解決(分例項,分庫分表),mongodb 原生提供叢集方案,該方案的簡要架構如下:

mongodb叢集是一個典型的去中心化分散式叢集。mongodb叢集主要為使用者解決了如下問題:

  • 元資料的一致性與高可用(Consistency + Partition Torrence)
  • 業務資料的多備份容災(由複製集技術保證)
  • 動態自動分片
  • 動態自動資料均衡

下文通過介紹 mongodb 叢集中各個組成部分,逐步深入剖析 mongodb 叢集原理。

ConfigServer

mongodb 元資料全部存放在configServer中,configServer 是由一組(至少三個)MongoDb例項組成的叢集。

ConfigServer 的唯一功能是提供元資料的增刪改查。和大多數元資料管理系統(etcd,zookeeper)類似,也是保證一致性與分割槽容錯性。本身不具備中心化的排程功能。

ConfigServer與複製集

ConfigServer 的分割槽容錯性(P)和資料一致性(C)是複製集本身的性質。

mongodb 的讀寫一致性由 WriteConcern 和 ReadConcern 兩個引數保證。

writeConcern

readConcern

兩者組合可以得到不同的一致性等級。

指定 writeConcern:majority 可以保證寫入資料不丟失,不會因選舉新主節點而被回滾掉。

readConcern:majority + writeConcern:majority 可以保證強一致性的讀

readConcern:local + writeConcern:majority 可以保證最終一致性的讀

mongodb 對configServer全部指定writeConcern:majority 的寫入方式,因此元資料可以保證不丟失。

對 configServer 的讀指定了 ReadPreference:PrimaryOnly 的方式,在 CAP 中捨棄了A與P得到了元資料的強一致性讀。

Mongos

資料自動分片

對於一個讀寫操作,mongos 需要知道應該將其路由到哪個複製集上,mongos通過將片鍵空間劃分為若干個區間,計算出一個操作的片鍵的所屬區間對應的複製集來實現路由。

Collection1 被劃分為4個chunk,其中

chunk1 包含(-INF,1) , chunk3 包含[20, 99) 的資料,放在shard1上。

chunk2 包含 [1,20), chunk4 包含[99, INF) 的資料,放在shard2上。

chunk 的資訊存放在configServer 的mongod例項的 config.chunks 表中,格式如下:

{   
    "_id" : "mydb.foo-a_\"cat\"",   
    "lastmod" : Timestamp(1000, 3),  
    "lastmodEpoch" : ObjectId("5078407bd58b175c5c225fdc"),   
    "ns" : "mydb.foo",   
    "min" : {         "animal" : "cat"   },   
    "max" : {         "animal" : "dog"   },   
    "shard" : "shard0004"
}

值得注意的是:chunk是一個邏輯上的組織結構,並不涉及到底層的檔案組織方式。

2.保證叢集總是可讀寫

  MongoDB通過多種途徑來確保叢集的可用性和可靠性。將MongoDB的分片和複製功能結合使用,在確保資料分片到多臺伺服器的同時,也確保了每分資料都有相應的備份,這樣就可以確保有伺服器換掉時,其他的從庫可以立即接替壞掉的部分繼續工作。

3.使叢集易於擴充套件

  當系統需要更多的空間和資源的時候,MongoDB使我們可以按需方便的擴充系統容量。

2.1.4 分片叢集架構

元件 說明
Config Server 儲存叢集所有節點、分片資料路由資訊。預設配置3個Config Server節點
Mongos 提供對外應用訪問,所有操作均需通過mongos執行,一般有多個mongos節點。資料遷移和資料自動平衡
Mongod 儲存應用資料記錄,一般有多個Mongod節點,達到資料分片的目的

分片叢集的構造

(1)mongos :資料路由,和客戶端打交道的模組。mongos本身沒有任何資料,他也不知道該怎麼處理這資料,去找config server

(2)config server:所有存、取資料的方式,所有shard節點的資訊,分片功能的一些配置資訊。可以理解為真實資料的元資料。

 (3)shard:真正的資料儲存位置,以chunk為單位存資料。

 Mongos本身並不持久化資料,Sharded cluster所有的元資料都會儲存到Config Server,而使用者的資料會分散儲存到各個shard。Mongos啟動後,會從配置伺服器載入元資料,開始提供服務,將使用者的請求正確路由到對應的碎片。

Mongos的路由功能

  當資料寫入時,MongoDB Cluster根據分片鍵設計寫入資料。

  當外部語句發起資料查詢時,MongoDB根據資料分佈自動路由至指定節點返回資料。

叢集中資料分佈

Chunk是什麼

  在一個shard server內部,MongoDB還是會把資料分為chunks,每個chunk代表這個shard server內部一部分資料。chunk的產生,會有以下兩個用途:

  Splitting當一個chunk的大小超過配置中的chunk size時,MongoDB的後臺程序會把這個chunk切分成更小的chunk,從而避免chunk過大的情況

  Balancing在MongoDB中,balancer是一個後臺程序,負責chunk的遷移,從而均衡各個shard server的負載,系統初始1個chunk,chunk size預設值64M,生產庫上選擇適合業務的chunk size是最好的。MongoDB會自動拆分和遷移chunks。

分片叢集的資料分佈(shard節點)

(1)使用chunk來儲存資料

(2)進群搭建完成之後,預設開啟一個chunk,大小是64M,

(3)儲存需求超過64M,chunk會進行分裂,如果單位時間儲存需求很大,設定更大的chunk

(4)chunk會被自動均衡遷移。

chunksize的選擇

  適合業務的chunksize是最好的。

  chunk的分裂和遷移非常消耗IO資源;chunk分裂的時機:在插入和更新,讀資料不會分裂。

  chunksize的選擇:

  小的chunksize:資料均衡是遷移速度快,資料分佈更均勻。資料分裂頻繁,路由節點消耗更多資源。大的chunksize:資料分裂少。資料塊移動集中消耗IO資源。通常100-200M

chunk分裂及遷移

  隨著資料的增長,其中的資料大小超過了配置的chunk size,預設是64M,則這個chunk就會分裂成兩個。資料的增長會讓chunk分裂得越來越多。

這時候,各個shard 上的chunk數量就會不平衡。這時候,mongos中的一個元件balancer 就會執行自動平衡。把chunk從chunk數量最多的shard節點挪動到數量最少的節點。

chunkSize對分裂及遷移的影響

  MongoDB 預設的 chunkSize 為64MB,如無特殊需求,建議保持預設值;chunkSize 會直接影響到 chunk 分裂、遷移的行為

  chunkSize 越小,chunk 分裂及遷移越多,資料分佈越均衡;反之,chunkSize 越大,chunk 分裂及遷移會更少,但可能導致資料分佈不均。可能造成熱點資料問題

  chunkSize 太小,容易出現 jumbo chunk(即shardKey 的某個取值出現頻率很高,這些文件只能放到一個 chunk 裡,無法再分裂)而無法遷移;chunkSize 越大,則可能出現 chunk 內文件數太多(chunk 內文件數不能超過 250000 )而無法遷移。

  chunk 自動分裂只會在資料寫入時觸發,所以如果將 chunkSize 改小,系統需要一定的時間來將 chunk 分裂到指定的大小。

  chunk 只會分裂,不會合並,所以即使將 chunkSize 改大,現有的 chunk 數量不會減少,但 chunk 大小會隨著寫入不斷增長,直到達到目標大小。

資料區分

分片鍵shard key

  MongoDB中資料的分片是以集合為基本單位的,集合中的資料通過片鍵(Shard key)被分成多部分。其實片鍵就是在集合中選一個鍵,用該鍵的值作為資料拆分的依據。

  所以一個好的片鍵對分片至關重要。片鍵必須是一個索引,通過sh.shardCollection加會自動建立索引(前提是此集合不存在的情況下)。一個自增的片鍵對寫入和資料均勻分佈就不是很好,因為自增的片鍵總會在一個分片上寫入,後續達到某個閥值可能會寫到別的分片。但是按照片鍵查詢會非常高效

  隨機片鍵對資料的均勻分佈效果很好。注意儘量避免在多個分片上進行查詢。在所有分片上查詢,mongos會對結果進行歸併排序。

  對集合進行分片時,你需要選擇一個片鍵,片鍵是每條記錄都必須包含的,且建立了索引的單個欄位或複合字段,MongoDB按照片鍵將資料劃分到不同的資料塊中,並將資料塊均衡地分佈到所有分片中

  為了按照片鍵劃分資料塊,MongoDB使用基於範圍的分片方式或者 基於雜湊的分片方式。

注意

分片鍵是不可變。

分片鍵必須有索引。

分片鍵大小限制512bytes。

分片鍵用於路由查詢。

MongoDB不接受已進行collection級分片的collection上插入無分片

鍵的文件(也不支援空值插入)

以範圍為基礎的分片Sharded Cluster

  Sharded Cluster支援將單個集合的資料分散儲存在多shard上,使用者可以指定根據集合內文件的某個欄位即shard key來進行範圍分片(range sharding)。

 對於基於範圍的分片,MongoDB按照片鍵的範圍把資料分成不同部分。

  假設有一個數字的片鍵:想象一個從負無窮到正無窮的直線,每一個片鍵的值都在直線上畫了一個點。MongoDB把這條直線劃分為更短的不重疊的片段,並稱之為資料塊,每個資料塊包含了片鍵在一定範圍內的資料。在使用片鍵做範圍劃分的系統中,擁有”相近”片鍵的文件很可能儲存在同一個資料塊中,因此也會儲存在同一個分片中。

基於雜湊的分片

  分片過程中利用雜湊索引作為分片的單個鍵,且雜湊分片的片鍵只能使用一個欄位,而基於雜湊片鍵最大的好處就是保證資料在各個節點分佈基本均勻。

對於基於雜湊的分片,MongoDB計算一個欄位的雜湊值,並用這個雜湊值來建立資料塊。在使用基於雜湊分片的系統中,擁有”相近”片鍵的文件很可能不會儲存在同一個資料塊中,因此資料的分離性更好一些。

  Hash分片與範圍分片互補,能將文件隨機的分散到各個chunk,充分的擴充套件寫能力,彌補了範圍分片的不足,但不能高效的服務範圍查詢,所有的範圍查詢要分發到後端所有的Shard才能找出滿足條件的文件。

分片鍵選擇建議

遞增的sharding key

資料檔案挪動小。(優勢)

因為資料檔案遞增,所以會把insert的寫IO永久放在最後一片上,造成最後一片的寫熱點。同時,隨著最後一片的資料量增大,將不斷的發生遷移至之前的片上。

隨機的sharding key

資料分佈均勻,insert的寫IO均勻分佈在多個片上。(優勢)

大量的隨機IO,磁碟不堪重荷。

混合型key

大方向隨機遞增,小範圍隨機分佈。

為了防止出現大量的chunk均衡遷移,可能造成的IO壓力。我們需要設定合理分片使用策略(片鍵的選擇、分片演算法(range、hash))

分片注意

分片鍵是不可變、分片鍵必須有索引、分片鍵大小限制512bytes、分片鍵用於路由查詢。

MongoDB不接受已進行collection級分片的collection上插入無分片鍵的文件(也不支援空值插入)

轉自:https://www.cnblogs.com/clsn/p/8214345.html#auto_id_0