隨著資料量不斷增長,單一 MongoDB 伺服器難以負荷日益增長的讀寫壓力。分片技術作為水平擴充套件方案,能有效分散資料及工作負載至多個伺服器,提升系統整體效能和可擴充套件性。本文將探討 MongoDB 分片技術的核心概念,包含分片鍵、區塊、範圍分片、雜湊分片以及平衡器等,並提供程式碼範例說明如何建立和管理分片叢集。同時,文章也將分析分片技術的優缺點,以及如何選擇合適的分片策略,以避免效能瓶頸並最大化系統效益。最後,文章將討論分片鍵的選擇、範圍分片與雜湊分片的比較、區域分片和分片平衡等最佳實務,協助讀者更好地理解和應用 MongoDB 分片技術。
分片技術在MongoDB中的應用與挑戰
隨著網路應用程式的不斷成長,資料函式庫需要處理的工作量也日益增加。當單一伺服器的處理能力達到極限時,擴充其能力成為必要。起初,我們可以透過將部分讀取工作轉移到次要節點來擴充伺服器的能力,但最終,寫入工作量仍會超過主節點的負荷能力。這時,我們需要採取「水平擴充套件」策略,也就是透過分片技術,將工作量分散到多個主節點上。
分片技術的重要性
分片技術是支援現代網路巨型網站運作的關鍵架構之一。Facebook和Twitter等大型網站都是分片技術的早期採用者,它們使用MySQL實作了大規模的分片。然而,分片技術並非毫無缺點,使用MySQL進行分片需要大量的手動組態,並且會破壞某些核心資料函式庫功能。相比之下,MongoDB的分片功能完全整合在核心資料函式庫中,組態和管理相對容易。
分片技術的核心概念
分片鍵(Shard Key):決設定檔案被放置在哪個分片中的屬性。分片鍵應具有高基數(即具有大量唯一值),以確保資料能夠均勻地分佈在各個分片中。
區塊(Chunks):檔案被包含在區塊中,而區塊被分配到特定的分片。區塊的存在避免了MongoDB需要費力地在分片之間移動單個檔案。
範圍分片(Range Sharding):連續的分片鍵群組被儲存在同一個區塊中。範圍分片允許高效的分片鍵範圍掃描,但如果分片值單調遞增,可能會導致「熱」區塊的出現。
雜湊分片(Hash Sharding):根據應用於分片鍵的雜湊函式來分佈鍵值。雜湊分片可以避免「熱」區塊,但可能會影響範圍查詢的效能。
平衡器(The Balancer):MongoDB嘗試保持每個分片所承擔的資料和工作量均衡。平衡器會定期將資料從一個分片移動到另一個分片,以維持這種平衡。
程式碼範例:建立分片叢集
// 初始化組態伺服器
configServer = new Mongod({
dbpath: "/data/configdb",
port: 27019,
});
// 初始化分片伺服器
shardServer1 = new Mongod({
dbpath: "/data/shard1",
port: 27020,
});
shardServer2 = new Mongod({
dbpath: "/data/shard2",
port: 27021,
});
// 初始化路由伺服器(mongos)
mongos = new Mongos({
configdb: "localhost:27019",
port: 27017,
});
// 將分片伺服器新增到叢集
mongos.adminCommand({ addShard: "localhost:27020" });
mongos.adminCommand({ addShard: "localhost:27021" });
// 對集合進行分片
mongos.adminCommand({ enablesharding: "mydatabase" });
mongos.adminCommand({ shardcollection: "mydatabase.mycollection", key: { _id: "hashed" } });
內容解密:
- 初始化組態伺服器:組態伺服器儲存了叢集的中繼資料,包括分片資訊和區塊分佈情況。
- 初始化分片伺服器:每個分片伺服器是一個獨立的MongoDB例項,負責儲存部分資料。
- 初始化路由伺服器(mongos):mongos是客戶端應用程式與分片叢集之間的橋樑,它根據分片鍵將請求路由到正確的分片。
- 將分片伺服器新增到叢集:透過
addShard命令,將分片伺服器新增到叢集中。 - 對集合進行分片:透過
shardcollection命令,對指定的集合進行分片,並指定分片鍵。
是否採用分片技術
分片技術是MongoDB中最複雜的組態拓撲之一,被一些世界上最大、最具效能的網站所採用。然而,分片技術並非總是能提升效能。事實上,分片增加了複雜性和處理開銷,在某些情況下甚至可能使個別操作變慢。只有當硬體資源成為瓶頸時,分片才可能成為最佳解決方案。
分片鍵的選擇
選擇正確的分片鍵對於分片專案的成功至關重要。理想的分片鍵應具有高基數、均勻分佈的值,並且頻繁出現在查詢中。同時,分片鍵應避免單調遞增,以防止「熱」區塊的出現。
範圍分片與雜湊分片的比較
範圍分片和雜湊分片各有其優缺點。範圍分片適合範圍查詢,但可能導致「熱」區塊。雜湊分片可以避免「熱」區塊,但可能會影響範圍查詢的效能。
範圍分片與雜湊分片比較
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title MongoDB分片技術應用與挑戰
package "資料庫架構" {
package "應用層" {
component [連線池] as pool
component [ORM 框架] as orm
}
package "資料庫引擎" {
component [查詢解析器] as parser
component [優化器] as optimizer
component [執行引擎] as executor
}
package "儲存層" {
database [主資料庫] as master
database [讀取副本] as replica
database [快取層] as cache
}
}
pool --> orm : 管理連線
orm --> parser : SQL 查詢
parser --> optimizer : 解析樹
optimizer --> executor : 執行計畫
executor --> master : 寫入操作
executor --> replica : 讀取操作
cache --> executor : 快取命中
master --> replica : 資料同步
note right of cache
Redis/Memcached
減少資料庫負載
end note
@enduml此圖示說明瞭範圍分片和雜湊分片的主要特點和適用場景。
總之,分片技術是MongoDB中一種強大的擴充套件能力手段,但需要謹慎選擇和組態。透過正確的分片策略,可以有效地提升資料函式庫的效能和可擴充套件性。
分片策略的最佳實踐
在 MongoDB 中,分片是一種水平擴充套件資料函式庫的方法,透過將資料分散到多個伺服器上來提高效能和可擴充套件性。選擇正確的分片策略對於確保資料均勻分佈和查詢效能至關重要。
根據範圍的分片與根據雜湊的分片
MongoDB 支援兩種主要的分片策略:根據範圍的分片(Range-based Sharding)和根據雜湊的分片(Hash-based Sharding)。
根據範圍的分片
根據範圍的分片根據分片鍵的值範圍將資料分配到不同的分片上。這種方法有利於執行範圍查詢,因為相關資料通常位於同一個分片上。然而,如果分片鍵是單調遞增的(如時間戳),那麼新的資料總是會被插入到同一個分片上,導致該分片成為熱點,降低了整體效能。
根據雜湊的分片
根據雜湊的分片透過對分片鍵進行雜湊運算來分配資料。這種方法能夠更均勻地將資料分佈在各個分片上,特別是在分片鍵是單調遞增的情況下。然而,雜湊分片可能會導致範圍查詢效能下降,因為相關資料可能分散在多個分片上。
// 建立雜湊索引以支援雜湊分片
db.collection.createIndex({ field: "hashed" });
內容解密:
db.collection.createIndex({ field: "hashed" }):為指定的欄位建立雜湊索引,這是實作雜湊分片的基礎。- 雜湊索引的作用:透過雜湊函式將欄位值轉換為雜湊值,使得資料能夠均勻分佈在不同的分片上。
- 適用場景:當分片鍵是單調遞增的值時,使用雜湊索引可以避免資料集中寫入某個分片,提高寫入效能。
區域分片
區域分片(Zone Sharding)允許管理員根據特定的規則將資料分配到特定的分片上。這種方法可以用來最佳化資料的地理分佈,將資料儲存在離使用者更近的資料中心,或者將冷資料儲存在較便宜的硬體上。
組態區域分片
建立區域:首先,需要為不同的地理區域或硬體型別建立區域。
sh.addShardToZone("shardRS2", "US"); sh.addShardToZone("shardRS", "TheWorld");內容解密:
sh.addShardToZone("shardRS2", "US"):將 shardRS2 分片新增到名為 “US” 的區域。sh.addShardToZone("shardRS", "TheWorld"):將 shardRS 分片新增到名為 “TheWorld” 的區域。- 區域的作用:根據業務需求,將不同的分片分配到不同的區域,以實作資料的地理分佈或硬體最佳化。
分配分片鍵範圍到區域:接下來,將特定的分片鍵範圍分配到對應的區域。
sh.addTagRange( "MongoDBTuningBook.customers", { "Country": "Afghanistan", "City": MinKey }, { "Country": "United Kingdom", "City": MaxKey }, "TheWorld" );內容解密:
sh.addTagRange():用於將特定的分片鍵範圍對映到指定的區域。MinKey和MaxKey:代表最小和最大的鍵值,用於定義範圍的起點和終點。- 對映規則:根據國家和城市欄位,將特定範圍內的資料分配到 “TheWorld” 區域。
分片平衡
使用 getShardDistribution() 方法可以檢查資料在各個分片上的分佈情況。一個良好的分片策略應該能夠均勻地將資料分佈在各個分片上,以避免某些分片成為效能瓶頸。
db.collection.getShardDistribution();
內容解密:
db.collection.getShardDistribution():顯示集合在各個分片上的資料分佈情況。- 檢查資料分佈:透過此命令,可以瞭解各個分片上的資料量和檔案數量,判斷是否需要調整分片策略。
- 最佳化目標:確保各個分片上的負載相對均衡,避免單個分片成為效能瓶頸。
MongoDB 分片叢集的資料分佈與平衡
在 MongoDB 的分片叢集中,資料的分佈與平衡對於確保系統的高效能和可擴充套件性至關重要。本篇文章將探討 MongoDB 分片叢集中的資料分佈、平衡機制以及如何管理和最佳化分片叢集。
資料分佈
MongoDB 的分片叢集透過將資料分散到多個分片(shard)上來實作水平擴充套件。每個分片都是獨立的 MongoDB 例項或副本集,儲存了部分資料。MongoDB 透過分片鍵(shard key)來決定如何將資料分配到不同的分片上。
分片鍵的選擇
選擇適當的分片鍵對於確保資料的均勻分佈至關重要。理想的分片鍵應該具有高基數(high cardinality)、均勻分佈(even distribution)、頻繁查詢(frequently queried)且非單調遞增(non-monotonically increasing)。如果分片鍵選擇不當,可能會導致某些分片上的資料量遠遠大於其他分片,從而形成「巨型」(jumbo)區塊。
資料平衡
MongoDB 提供了一個自動平衡機制,用於在分片之間重新分配資料。當某個分片上的區塊數量或資料量與其他分片相比存在較大差異時,平衡器(balancer)會自動啟動,將區塊從資料量較大的分片遷移到資料量較小的分片,以實作資料的重新平衡。
平衡器的運作機制
平衡器會根據分片之間的區塊數量差異來決定是否需要進行資料遷移。例如,如果某個分片上的區塊數量比其他分片多出一定閾值(該閾值取決於總區塊數量),平衡器就會開始遷移區塊。遷移過程中,MongoDB 會確保資料的一致性和可用性。
管理和最佳化分片叢集
雖然 MongoDB 的自動平衡機制可以有效地維護資料的分佈,但仍有一些情況下需要手動干預或最佳化。
修改平衡視窗
預設情況下,平衡器會持續運作以維護資料的平衡。然而,在某些情況下,例如在應用程式負載較高的期間,可能需要限制平衡器的運作時間。MongoDB 允許管理員設定平衡視窗,以控制平衡器在特定時間段內運作。
mongos> use config
switched to db config
mongos> db.settings.update(
... { _id: "balancer" },
... { $set: { activeWindow: { start: "22:30", stop: "04:00" } } },
... { upsert: true })
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
#### 內容解密:
此段程式碼的作用是修改 MongoDB 分片叢集的平衡視窗,使平衡器僅在晚上 10:30 至凌晨 4:00 之間運作。這樣可以避免在應用程式負載較高的期間進行資料遷移,從而減少對系統效能的影響。
use config:切換到config資料函式庫,因為平衡器的設定儲存在此資料函式庫中。db.settings.update():更新settings集合中的檔案,以修改平衡視窗的設定。{ _id: "balancer" }:指定要更新的檔案 ID 為balancer,這是 MongoDB 內部用於儲存平衡器設定的 ID。{ $set: { activeWindow: { start: "22:30", stop: "04:00" } } }:設定新的平衡視窗,從晚上 10:30 開始,到凌晨 4:00 結束。{ upsert: true }:如果指定的檔案不存在,則建立一個新的檔案;如果已存在,則更新該檔案。
停用和啟用平衡器
在某些情況下,例如在進行大量資料匯入或維護操作時,可能需要臨時停用平衡器,以避免不必要的效能開銷。MongoDB 提供了停用和啟用平衡器的功能。
mongos> sh.getBalancerState()
true
mongos> sh.stopBalancer()
{
"ok" : 1,
...
}
mongos> sh.startBalancer()
#### 內容解密:
此段程式碼示範瞭如何檢查、停用和啟用 MongoDB 分片叢集的平衡器。
sh.getBalancerState():檢查當前平衡器的狀態。如果傳回true,表示平衡器正在執行;如果傳回false,表示平衡器已停止。sh.stopBalancer():停止平衡器,以避免在進行大量資料操作時發生不必要的資料遷移。sh.startBalancer():重新啟動平衡器,以繼續維護資料的分佈平衡。
MongoDB 叢集平衡與查詢最佳化
在 MongoDB 的分散式架構中,資料的平衡分佈對於整體效能至關重要。本章將探討如何管理和最佳化叢集中的資料分佈,以及如何分析分散式查詢的執行計畫。
平衡器的控制與調整
MongoDB 的平衡器負責在各個分片之間重新分配資料區塊(chunks)。適當地控制平衡器對於維持叢集效能至關重要。
啟動與停止平衡器
// 檢查平衡器狀態
sh.getBalancerState()
// 啟動平衡器
sh.startBalancer()
// 停止平衡器
sh.stopBalancer()
更改區塊大小
預設的區塊大小為 64MB,可以根據實際需求進行調整。較小的區塊大小會增加遷移次數和查詢路由時間,但可以實作更均勻的資料分佈。
// 設定區塊大小(範例:將區塊大小設定為 32MB)
config = db.getSiblingDB("config")
config.settings.save({_id: "chunksize", value: 32})
內容解密:
sh.getBalancerState()用於檢查當前平衡器的狀態。sh.startBalancer()和sh.stopBalancer()分別用於啟動和停止平衡器。- 更改區塊大小需要修改
config.settings集合中的chunksize欄位。
調整分片鍵
選擇合適的分片鍵對於資料的均勻分佈至關重要。如果發現現有的分片鍵導致效能問題,可以考慮更改或改進分片鍵。
更改分片鍵的步驟
- 備份資料
- 刪除整個集合
- 使用新的分片鍵重新建立集合
- 匯入舊資料
改進分片鍵(Refining Shard Key)
從 MongoDB 4.4 版本開始,支援在不重新建立集合的情況下改進現有的分片鍵。
// 改進分片鍵範例
db.adminCommand({
refineCollectionShardKey: "MongoDBTuningBook.customersSCountry",
key: { Country: 1, District: 1 }
})
內容解密:
- 改進分片鍵需要在新的分片鍵屬性上建立相應的索引。
- 改進後的分片鍵可以提高資料分佈的粒度,減少巨型區塊(jumbo chunks)的出現。
- 注意,改進分片鍵不會立即影響資料分佈,需要等待平衡器進行重新平衡。
分散式查詢的最佳化
分散式查詢的效能對於整體系統的效能有著重要影響。使用 explain() 方法可以分析查詢的執行計畫。
分析分散式查詢的執行計畫
var exp = db.customers.explain('executionStats')
.find({'views.title':'PRINCESS GIANT'}).next()
內容解密:
- 使用
explain('executionStats')可以獲得查詢執行的詳細統計資訊。 - 在分散式查詢中,需要關注
SHARD_MERGE和各個分片上的執行階段。 - 分析查詢執行計畫有助於最佳化查詢效能和調整索引。