亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

怎么選擇MongoDB的分片字段

怎么選擇MongoDB的分片字段

繁花不似錦 2019-05-14 09:08:53
怎么選擇MongoDB的分片字段
查看完整描述

3 回答

?
翻翻過去那場雪

TA貢獻2065條經驗 獲得超14個贊

  將存儲在MongoDB數據庫中的Collection進行分片需要選定分片Key(Shard key),對于分片Key的選定直接決定了集群中數據分布是否均衡、集群性能是否合理。那么我們究竟該選擇什么樣的字段來作為分片Key呢?有如下幾個需要考慮點。
  以下述記錄日志的Document為例:
  {

  server : "ny153.example.com" ,
  application : "apache" ,
  time : "2011-01-02T21:21:56.249Z" ,
  level : "ERROR" ,
  msg : "something is broken"
  }
  基數
  Mongodb中一個被分片的Collection的所有數據都存放在眾多的Chunk中。一個Chunk存放分片字段的一個區間范圍的數據。選擇一個好的分片字段非常重要,否則就會遭遇到不能被拆分的大Chunk。
  用上述的日志為例,如果選擇{server:1}來作為一個分片Key的話,一個server上的所有數據都是在同一個Chunk中,很容易想到一個Server上的日志數據會超過200MB(默認Chunk大?。?。如果分片Key是{server:1,time:1},那么能夠將一個Server上的日志信息進行分片,直至毫秒級別,絕對不會存在不可被拆分的Chunk。
  將Chunk的規模維持在一個合理的大小是非常重要的,只有這樣數據才能均勻分布,并且移動Chunk的代價也不會過大。
  寫操作可擴展
  使用分片的一個主要原因之一是分散寫操作。為了實現這個目標,盡可能的將寫操作分散到多個Chunk就尤為重要了。
  用上述的日志實例,選擇{time:1}來作為分片key將導致所有的寫操作都會落在最新的一個Chunk上去,這樣就形成了一個熱點區域。如果選擇{server:1,application:1,time:1}來作為分片Key的話,那么每一個Server上的應用的日志信息將會寫在不同的地方,如果有100個Server和應用對,有10臺Server,那么每一臺Server將會分擔1/10的寫操作。
  查詢隔離
  另外一個需要考慮的是任何一個查詢操作將會由多少個分片來來提供服務。最理想的情況是,一個查詢操作直接從Mongos進程路由到一個Mongodb上去,并且這個Mongodb擁有該次查詢的全部數據。因此,如果你知道最為通用的查詢操作的都以server作為一個查詢條件的話,以Server作為一個起始的分片Key會使整個集群更加高效。
  任何一個查詢都能執行,不管使用什么來作為分片Key,但是,如果Mongos進程不知道是哪一個Mongodb的分片擁有要查詢的數據的話,Mongos將會讓所有的Mongod分片去執行查詢操作,再將結果信息匯總起來返回。顯而易見,這回增加服務器的響應時間,會增加網絡成本,也會無謂的增加了Load。
  排序
  在需要調用sort()來查詢排序后的結果的時候,以分片Key的最左邊的字段為依據,Mongos可以按照預先排序的結果來查詢最少的分片,并且將結果信息返回給調用者。這樣會花最少的時間和資源代價。
  相反,如果在利用sort()來排序的時候,排序所依據的字段不是最左側(起始)的分片Key,那么Mongos將不得不并行的將查詢請求傳遞給每一個分片,然后將各個分片返回的結果合并之后再返回請求方。這個會增加Mongos的額外的負擔。
  可靠性
  選擇分片Key的一個非常重要因素是萬一某一個分片徹底不可訪問了,受到影響的Chunk有多大(即使是用貌似可以信賴的Replica Set)。
  假定,有一個類似于Twiter的系統,Comment記錄類似如下形式:
  {

  _id: ObjectId("4d084f78a4c8707815a601d7"),
  user_id : 42 ,
  time : "2011-01-02T21:21:56.249Z" ,
  comment : "I am happily using MongoDB",
  }
  由于這個系統對寫操作非常敏感,所以需要將寫操作扁平化的分布到所有的Server上去,這個時候就需要用id或者user_id來作為分片Key了。使用Id作為分片Key有最大粒度的扁平化,但是在一個分片宕機的情況下,會影響幾乎所有的用戶(一些數據丟失了)。如果使用User_id作為分片Key,只有極少比率的用戶會收到影響(在存在5個分片的時候,20%的用戶受影響),但是這些用戶會再也不會看到他們的數據了。
  索引優化
  正如在別的章節中提到索引的一樣,如果只有一部分的索引被讀或者更新的話,通常會有更好的性能,因為“活躍”的部分在大多數時間內能駐留在內存中。本文上述的所描述的選擇分片Key的方法都是為了最終數據能夠均勻的分布,與此同時,每一個Mongod的索引信息也被均勻分布了。相反,使用時間戳作為分片key的起始字段會有利于將常用索引限定在較小的一部分。
  假定有一個圖片存儲系統,圖片記錄類似于如下形式:
  {

  _id: ObjectId("4d084f78a4c8707815a601d7"),
  user_id : 42 ,
  title: "sunset at the beach",
  upload_time : "2011-01-02T21:21:56.249Z" ,
  data: ...,
  }
  你也能構造一個客戶id,讓它包括圖片上傳時間對應的月度信息和一個唯一標志符(ObjectID,數據的MD5等)。記錄看起來就像下面這個樣子的:
  {
  _id: "2011-01-02_4d084f78a4c8707815a601d7",

  user_id : 42 ,

  title: "sunset at the beach",

  upload_time : "2011-01-02T21:21:56.249Z" ,

  data: ...,

  }

  客戶id作為分片key,并且這個id也被用于去訪問這個Document。即能將數據均衡的分布在各個節點上,也減少了大多數查詢所使用的索引比例。
  更進一步來講:
  在每一個月份的開始,在開最初的一段時間內只有一個Server來存取數據,隨著數據量的增長,負載均衡器(balancer)就開始進行分裂和遷移數據塊了。為了避免潛在的低效率和遷移數據,預先創建分片范圍區間是明智之舉。(如果有5個Sever則分5個區間)
  可以繼續改進,可以把User_ID包含到圖片的id中來。這樣的話會讓一個用戶的所有Document都在一個分片上。比如用“2011-01-02_42_4d084f78a4c8707815a601d7”作為圖片的id。
  GridFS
  根據需求的不同,GridFS有幾種不同的分片方法?;陬A先存在的索引是慣用的分片辦法:
  1)“files”集合(Collection)不會分片,所有的文件記錄都會位于一個分片上,高度推薦使該分片保持高度靈活(至少使用由3個節點構成的replica set)。
  2)“chunks”集合(Collection)應該被分片,并且用索引”files_id:1”。已經存在的由MongoDB的驅動來創建的“files_id,n”索引不能用作分片Key(這個是一個分片約束,后續會被修復),所以不得不創建一個獨立的”files_id”索引。使用“files_id”作為分片Key的原因是一個特定的文件的所有Chunks都是在相同的分片上,非常安全并且允許運行“filemd5”命令(要求特定的驅動)。
  運行如下命令:
  > db.fs.chunks.ensureIndex({files_id: 1});

  > db.runCommand({ shardcollection : "test.fs.chunks", key : { files_id : 1 }})

  { "collectionsharded" : "test.fs.chunks", "ok" : 1 }

  由于默認的files_id是一個ObjectId,files_id將會升序增長,因此,GridFS的全部Chunks都會被從一個單點分片上存取。如果寫的負載比較高,就需要使用其他的分片Key了,或者使用其它的值(_id)來作為分片Key了。
  
  選擇分片Key的需要考慮的因素具有一定的對立性,不可能樣樣的具備,在實際使用過程中還是需要根據需求的不同來進行權衡,適當放棄一些。沒有萬能的普適分片辦法





查看完整回答
反對 回復 2019-05-15
?
白豬掌柜的

TA貢獻1893條經驗 獲得超10個贊

Mongodb中一個被分片的Collection的所有數據都存放在眾多的Chunk中。一個Chunk存放分片字段的一個區間范圍的數據。選擇一個好的分片字段非常重要,否則就會遭遇到不能被拆分的大Chunk。
用上述的日志為例,如果選擇{server:1}來作為一個分片Key的話,一個server上的所有數據都是在同一個Chunk中,很容易想到一個Server上的日志數據會超過200MB(默認Chunk大小)。如果分片Key是{server:1,time:1},那么能夠將一個Server上的日志信息進行分片,直至毫秒級別,絕對不會存在不可被拆分的Chunk。
將Chunk的規模維持在一



查看完整回答
反對 回復 2019-05-15
?
慕尼黑8549860

TA貢獻1818條經驗 獲得超11個贊

分片是MongoDB提供的一種機制,其可以將大型的集合分割保存到不同的服務器上。與其他的分區方案相比,MongoDB幾乎能自動為我們完成所有事情。只要我們進行簡單的配置,并告訴MongoDB要分配的數據,它就可以自動維護數據在不同服務器之間的平衡。同時根據需要增減服務器,MongoDB也會自動移動平移已有數據。
分片機制提供了如下三種優勢
1. 對集群進行抽象,讓集群“不可見”。
MongoDB自帶了一個叫做mongos的專有路由進程。mongos就是掌握統一路口的路由器,其會將客戶端發來的請求準確無誤的路由到集群中的一個或者一組服務器上,同時會把接收到的響應拼裝起來發回到客戶端。
2.保證集群總是可讀寫。
MongoDB通過多種途徑來確保集群的可用性可靠性。將MongoDB的分片和復制功能結合使用,在確保數據分片到多臺服務器的同時,也確保了每分數據都有相應的備份,這樣就可以確保有服務器換掉時,其他的副本可以立即接替壞掉的部分繼續工作。
3.使集群易于擴展。
當系統需要更多的空間和資源的時候,MongoDB使我們可以按需方便的擴充系統容量。
實現數據分割
分片(shard)是集群中存儲集合數據子集的一臺或者多臺服務器。在生產環境中一個分片通常是一個副本集(replica set)。

片鍵(key),MongoDB以其作為依據來確定需要在不同分片服務器之間移動的數據。例如我們可以選擇用戶名(username)字段作為分片鍵,現有一用戶名區間[“p”,”z”],那么wufengtinghai是屬于這一區間的,那么數據最終會保存到與此區間對應的分片服務器上。
分配數據到分片服務器
分配數據到分片服務器可以使用不同的方式,了解不同的方式可以加深我們對MongoDB使用方式的理解。
一分片一區間
分配數據到分片最簡單的方式莫過于一個區間一個分片。假設我們有四個分片存儲用戶的相關信息,則我們可能會得到如下的分片和區間的對應關系。

這種分片方式非常簡單易懂,但是在一個大型繁忙的系統中卻會帶來許多的不便。假如大量的用戶使用首字母在【“a”,”f”)中的名字來注冊,這將會導致分片1比較大,因此需要將其一部分文檔移動到分片2上,我們可以調整分片1對應區間【”a”,”c”),使分片2的區間變成【”c”,”n”)。

如果移動數據后,分片2因此過載怎么辦?假設分片1和分片2各有500G數據,而分片3和分片4各自有300G數據。那么按照這個方案,最終需要一連串的復制,總共算下來需要移動400G數據,考慮到需要在集群的服務器之間移動這些數據,可見移動數據量之大。

如果需要新加分片服務器進行水平擴展呢?假設此時每個分片上都有了500G數據,那么我們現在需要將分片4上的400G數據移動到分片5,將分片3的300G數據移動到分片4,將分片2的200G數據移動到分片3,將分片1的100G數據移動到分片2,整整移動了1T的數據!

隨著分片數量和數據量的增長,這種噩夢將會持續下去,因此MongoDB不會采用這種方式。
一分片多區間
如果我們采用一分片多區間的方式,我們可以將分片1上的數據劃分為兩個區間,【”a”,”d”)包含400G數據,【”d”,”f”)包含100G數據,同樣我們也可以對分片2做類似的處理,得到區間【”f”,”j”)和【“j”,”n”)?,F在我們只需要將分片1上的【”d”,”f”)數據移動到分片4,將分片2的【“j”,”n”)的數據移動到分片3。這樣我們僅僅只需要移動200G數據。

如果要添加新分片,可以從每個分片頂端取100G數據并將其移動到新的分片上,這樣僅僅只需要移動400G數據即可。

MongoDB就是利用這種方式,當一個分片的數據越來越大時,其會自動分割片鍵區間,并將分片的數據進行分割并移動到其他分片。

 




查看完整回答
反對 回復 2019-05-15
  • 3 回答
  • 0 關注
  • 703 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號