隨著 MongoDB 應用日益廣泛,效能管理成為關鍵課題。本文系統化地闡述 MongoDB 效能調校方法,涵蓋應用程式碼、資料函式庫設計、索引、記憶體及 IO 子系統等多個層面。文章首先分析 MongoDB 的成功因素和效能挑戰,接著提出系統化調校的步驟,強調從應用層到儲存層的逐層最佳化。同時,也深入解析 MongoDB 的架構和核心概念,包括檔案模型、集合、JSON 與 BSON 的區別,為讀者提供全面的 MongoDB 效能調校。
MongoDB效能管理的重要性與挑戰
當MongoDB於2009年問世時,資料函式庫技術正處於十字路口。二十多年來,諸如Oracle、SQL Server和MySQL等關聯式資料函式庫一直主導著資料函式庫市場。這些結合了關聯式資料模型、SQL語言和「ACID」交易的資料函式庫,曾經是改變現代商業和推動網際網路革命的應用程式的基礎。然而,到本世紀第一個十年的中期,關聯式資料函式庫顯然無法滿足新一代始終線上、全球可擴充套件的網頁應用程式的需求。這些新的「Web 2.0」應用程式需要新型的資料函式倉管理系統。
NoSQL的崛起與MongoDB的成功
到2010年,許多非關聯式的「NoSQL」系統如雨後春筍般湧現——Hadoop、HBase、Cassandra等。在這些非關聯式的新秀中,MongoDB幾乎以任何衡量標準來說都是最成功的。截至目前,MongoDB躋身前五大資料函式倉管理系統之一。
MongoDB成功的關鍵因素
- 與物件導向程式設計正規化的契合:MongoDB的資料模型與物件導向程式設計緊密結合,使得開發者能夠更自然地與資料函式庫互動。
- 與現代DevOps實踐的相容性:MongoDB支援現代DevOps實踐,如快速迭代和持續整合/持續佈署(CI/CD),使得開發流程更加敏捷。
- 簡化開發者工作:MongoDB透過簡化資料存取和操作,使得開發者能夠專注於應用邏輯而非繁瑣的資料函式庫操作。
效能管理的重要性
隨著MongoDB日漸成熟並擴充套件其在企業中的應用,效能管理變得越來越重要。眾所周知,效能不佳的客戶面對應用程式可能對當今的線上企業造成致命打擊。例如,當網頁的載入時間從1秒增加到5秒時,使用者放棄該頁面的機率會增加90%,直接影響線上收入。而由於資料函式庫執行大量的磁碟I/O和資料處理,資料函式庫往往是效能不佳的根源。
MongoDB效能最佳化的挑戰
- 分片(Sharding):如何有效地對資料進行分片,以支援大規模的資料儲存和查詢。
- 索引最佳化:如何設計和最佳化索引,以提高查詢效能。
- 聚合操作(Aggregations):如何高效地執行聚合操作,以滿足複雜的資料分析需求。
內容解密:
本段落主要闡述了MongoDB在現代資料函式庫領域的重要性,以及其在效能管理上面臨的挑戰。首先介紹了MongoDB的背景和成功因素,接著討論了效能管理的重要性,最後指出了MongoDB在效能最佳化上面臨的一些挑戰。透過這樣的分析,可以幫助讀者更好地理解MongoDB的核心價值和實際應用中的關鍵問題。
此圖示展示了MongoDB的主要最佳化方向,包括分片、索引最佳化和聚合操作,每一方向都對應著特定的最佳化目標。
方法論的效能調校
效能是任何應用程式成功的關鍵因素。想想你每天使用的應用程式,很明顯你只會使用效能良好的應用程式。如果Google搜尋需要2分鐘,而Bing幾乎是即時的,你還會使用Google嗎?當然不會。事實上,研究表明,如果一個網頁載入時間超過3秒,大約一半的人會放棄存取該網站。
應用效能的關鍵
應用程式的效能取決於多個因素,但最常見的可避免的效能不佳原因是資料函式庫。將資料從磁碟移到資料函式庫,然後再從資料函式庫移到應用程式,涉及應用程式基礎架構中最慢的元件——磁碟機和網路。因此,應用程式與資料函式庫互動的程式碼以及資料函式庫本身的調校對於最佳效能至關重要。
一個警示故事
你的MongoDB調校方法論對於最終調校工作的成功至關重要。考慮以下警示故事。
一個由MongoDB資料函式庫支援的重要網站正在表現出無法接受的效能。作為一位經驗豐富的MongoDB專業人士,你被邀請來診斷問題。當你檢視關鍵的作業系統效能指標時,有兩件事情很突出:複本集主伺服器的CPU和IO都很高。CPU負載平均值和磁碟IO延遲都表明MongoDB系統需要更多的CPU和IO容量。
內容解密:
這段文字描述了一個由MongoDB資料函式庫支援的網站出現效能問題的案例。作者強調了效能調校的重要性,並透過一個實際案例來說明不當的效能調校可能帶來的後果。文中提到的CPU負載平均值和磁碟IO延遲是衡量系統效能的關鍵指標,它們對於判斷系統是否需要升級或調校至關重要。
本文的結構安排
本文分為以下幾個主要部分:
- 第1-3章涵蓋方法和技術。這些章節描述了一種效能調校方法論,我們相信這種方法提供了最有效的MongoDB資料函式庫調校手段。同時,也提供了一些關於MongoDB架構和工具的背景知識,這些工具可用於調查、監控和診斷MongoDB效能。
- 第4和5章涵蓋應用程式和資料函式庫設計。在這裡,我們討論了開發高效檔案模型和索引MongoDB集合的基礎知識。
- 第6-10章涵蓋應用程式碼的最佳化。調校應用程式碼通常提供最顯著的資料函式庫效能機會,應在調整伺服器或叢集組態之前進行。我們將研究如何最佳化MongoDB的
find()陳述式、聚合管道和資料操作陳述式。 - 第11-14章討論了MongoDB伺服器及其執行硬體的最佳化。我們將解釋如何最佳化記憶體以避免IO,如何最佳化無法避免的IO,以及最終如何組態高效的MongoDB叢集。
內容解密:
本文的結構安排反映了效能調校的系統方法,從基礎的方法論到具體的最佳化技術,涵蓋了從應用程式設計到伺服器組態的多個方面。這種安排有助於讀者全面理解MongoDB效能調校的各個環節。
本文的目標讀者
本文適用於任何對改善MongoDB資料函式庫或依賴該資料函式庫的應用程式效能感興趣的人。這包括應用架構師、開發人員和資料函式倉管理員。
雖然本文呈現了一種連貫且邏輯嚴密的自上而下的資料函式庫調校方法,但並非所有章節都同樣吸引所有讀者。例如,開發人員可能會發現有關應用程式碼的最佳化章節比有關IO最佳化的章節更有幫助。同樣,沒有存取應用程式碼的資料函式倉管理員可能會發現有關伺服器最佳化的章節更有用。
內容解密:
本文試圖滿足不同讀者群體的需求,包括開發人員和資料函式倉管理員。同時,也強調了在處理效能問題時,應該首先解決根本原因,而不是僅僅緩解症狀。
指令碼和範例資料
本文使用了各種腳原本報告MongoDB效能。所有這些指令碼都可以在GitHub上的https://github.com/gharriso/MongoDBPerformanceTuningBook找到。
主要的mongoTuning.js指令碼提供了從MongoDB shell會話中存取所有這些指令碼的方法。要在MongoDB shell中使用這些指令碼,只需發出帶有指令碼名稱作為引數的Mongo命令,並新增“–shell”選項。
內容解密:
這段文字介紹了本文所使用的指令碼和範例資料的位置和使用方法。這對於讀者實踐本文中的示例和實驗非常重要。透過使用這些指令碼,讀者可以更深入地瞭解如何監控和調校MongoDB的效能。
資料函式庫效能調校的層次化思考
在進行資料函式庫效能調校時,許多技術人員容易陷入「頭痛醫頭,腳痛醫腳」的窘境。以MongoDB為例,若未正確診斷問題根源,可能會導致錯誤的調校方向,甚至造成更大的資源浪費與效能下降。
效能調校的錯誤示範
曾經有技術人員面對MongoDB效能問題時,為瞭解決高CPU與IO負載,直接建議將資料函式庫進行分片(Sharding),分散至四台伺服器上。雖然短期內網站效能得到改善,但隨後卻發現每個分片節點都面臨容量耗盡的問題。後來邀請另一位專家進行複查後才發現,原本只需要調整索引就能解決原始效能問題,不僅無需額外硬體成本,也沒有停機風險。更糟糕的是,分片反而對某些查詢造成了負面影響。
這個案例顯示出**症狀式效能調校(Symptomatic Performance Tuning)**的危險性:
- 處理表面症狀,而非根本原因
- 傾向於採用硬體擴充方案,而非更具成本效益的組態或應用程式最佳化
- 無法獲得持久或可擴充套件的解決方案
系統化效能調校的重要性
為了避免上述問題,應該採用**系統化效能調校(Systematic Performance Tuning)**的方法,從上而下地分析資料函式庫請求的處理流程:
- 應用層傳送請求至MongoDB,並接收傳回的結果
- 資料函式庫層解析請求,進行許可權驗證、資源分配等操作,這些操作會消耗系統資源(CPU、記憶體)並可能產生並發爭用
- 資料存取層根據資料函式庫設計(檔案結構與索引)及查詢陳述式,決定需要處理的資料量
- 記憶體存取:部分資料會直接從記憶體中讀取(邏輯讀取)
- 磁碟存取:若資料不在記憶體中,則需從磁碟讀取(實體讀取),這是效能開銷最大的操作
每一層的操作都會影響到下一層的負載。若查詢陳述式未能有效利用索引,將導致過多的邏輯讀取,最終引發大量的實體讀取。因此,調校工作的順序至關重要。
系統化調校的三步驟
- 最佳化應用程式需求:調整資料函式庫請求與資料函式庫設計(索引與檔案模型),將應用程式對資料函式庫的需求降至最低
- 最佳化記憶體使用:減少實體IO操作,提高快取命中率
- 組態IO子系統:在前兩步最佳化後,根據實際的IO需求,提供足夠的IO頻寬並均勻分配負載
MongoDB的架構層次
MongoDB和其他資料函式庫系統一樣,由多個程式碼層組成,如圖1-1所示。瞭解這些層次有助於我們更有條理地進行效能調校。
圖1-1 MongoDB應用程式的關鍵層次示意圖
此圖示展示了MongoDB應用程式的主要組成層次,包括應用層、資料函式庫層、儲存層等,每一層都有其特定的功能與效能考量。
MongoDB 效能調校的系統化方法
效能調校是確保 MongoDB 資料函式庫高效執行的關鍵步驟。調校過程涉及多個層面,從應用程式層到儲存子系統,每一層的效能都對整體系統有著重要影響。
資料函式庫效能的層級結構
在探討 MongoDB 效能調校之前,瞭解資料函式庫的層級結構是必要的。資料函式庫效能可以分為以下幾個層級:
應用程式層:這是第一層,儘管你可能認為應用程式碼不屬於資料函式庫的一部分,但它仍然執行資料函式庫驅動程式碼,是資料函式庫效能的重要組成部分。應用程式層定義了資料模型(schema)和資料存取邏輯。
MongoDB 資料函式庫伺服器:資料函式庫伺服器包含處理 MongoDB 命令、維護索引和管理分散式叢集的程式碼。
儲存引擎:儲存引擎是資料函式庫的一部分,但也是獨立的程式碼層。在 MongoDB 中,有多種儲存引擎可供選擇,如記憶體儲存引擎、RocksDB 和 MMAP,但通常由 WiredTiger 儲存引擎代表。儲存引擎負責將資料快取在記憶體中。
儲存子系統:儲存子系統不屬於 MongoDB 程式碼函式庫的一部分,它由作業系統或儲存硬體實作。在簡單的單伺服器組態中,它由檔案系統和磁碟裝置的韌體代表。
調校原則
調校資料函式庫效能時,必須遵循從上層到下層的原則,即先最佳化上層再調整下層。每一層的負載都由其上一層決定,因此在未確保上層最佳化之前調整下層通常是錯誤的。
最小化應用程式工作負載
最小化應用程式對資料函式庫的需求是首要目標。我們希望資料函式庫以最少的處理滿足應用程式的資料需求。主要有兩種技術來減少應用程式工作負載:
- 調校應用程式碼:這可能涉及更改應用程式碼,使其發出更少的資料函式庫請求。例如,使用客戶端快取。然而,更常見的是重新編寫特定的 MongoDB 資料函式庫呼叫,如
find()或aggregate()。 - 調校資料函式庫設計:這涉及修改索引或更改個別集合中使用的檔案模型。
這些技術不僅是調校工作的邏輯起點,也代表了能夠提供最劇烈效能改進的方法。應用程式調校不時能夠帶來 100 甚至 1000 倍的效能改進,這種程度的改進在最佳化記憶體或調整實體磁碟佈局時很少見。
減少實體 IO
在最小化應用程式需求之後,我們關注減少等待 IO 的時間。換句話說,在嘗試減少每次 IO 的時間(IO 延遲)之前,我們試圖減少 IO 請求的數量。減少 IO 量幾乎總是能夠減少 IO 延遲,因此首先攻擊 IO 量是雙重有效的。
大多數實體 IO 發生在應用程式會話請求資料以滿足查詢或資料修改請求時。為 WiredTiger 快取和其他記憶體結構分配足夠的記憶體是減少實體 IO 的最重要步驟。
最佳化磁碟 IO
在規範化應用程式工作負載並組態可用記憶體以最小化導致實體 IO 的邏輯 IO 之後,才有必要確保磁碟 IO 子系統能夠應對挑戰。最佳化磁碟 IO 子系統可能是一個複雜和專業的任務,但基本原則是直接的:
- 確保 IO 子系統具有足夠的頻寬來應對實體 IO 需求。
- 在已分配的磁碟上均勻分配負載,最好的方法是使用 RAID 0(條帶化)。
- 在雲端環境中,通常不需要擔心條帶化的機制,但仍需要確保已分配的總 IO 頻寬足夠。
IO 子系統過載的明顯症狀是對 IO 請求的回應延遲過高。最佳化磁碟 IO 的過程在後續章節中有詳細介紹。
MongoDB 叢集調校與架構解析
叢集調校的重要性
在單一例項的 MongoDB 佈署和叢集佈署中,前述的所有因素均同等適用。然而,叢集化的 MongoDB 引入了額外的挑戰和機遇。例如:
- 在標準的副本集組態中(即單一主節點和多個從節點),需要在效能、一致性和資料完整性之間進行權衡。讀取關注(read concern)和寫入偏好(write preference)引數控制著資料如何被寫入和從從節點讀取。調整這些引數可以提高效能,但也可能導致在容錯移轉過程中發生資料丟失或讀取到過時資料的風險。
- 在分片的副本集中,有多個主節點,這允許更大的可擴充套件性和更好的效能,特別是對於具有高交易率的非常大的資料函式庫。然而,分片不一定是最具成本效益的方式來實作效能結果,而且確實涉及效能權衡。如果您決定分片,選擇分片鍵(shard key)和確定要分片的集合對於您的成功至關重要。
我們將在第13章和第14章中詳細討論叢集組態和調校。
系統最佳化步驟
面對 IO 密集型的資料函式庫時,人們很容易立即處理最明顯的症狀——IO 子系統。不幸的是,這通常只是治標不治本,而且往往代價高昂且最終無效。因為一個資料函式庫層中的問題可以由更高層的組態引起或解決,所以最佳化 MongoDB 資料函式庫最有效的方法是先調整上層,然後再調整下層:
- 透過最佳化資料函式庫請求和調整資料函式庫設計(索引和檔案建模)將應用程式的需求降至邏輯上的最低限度。
- 在降低了對資料函式庫的需求之後,最佳化記憶體以盡可能避免實體 IO。
- 現在實體 IO 的需求已經變得合理了,透過提供足夠的 IO 頻寬並均勻分配負載來組態 IO 子系統以滿足需求。
MongoDB 架構與核心概念
本章旨在讓您瞭解後續章節中參照的 MongoDB 架構和內部原理,這些對於 MongoDB 效能調校是必要的。一個 MongoDB 調校專業人員應該廣泛熟悉 MongoDB 技術的以下主要領域:
- MongoDB 檔案模型
- MongoDB 應用程式如何透過 MongoDB API 與 MongoDB 資料函式庫伺服器互動
- MongoDB 最佳化器,這是與最大化 MongoDB 請求效能相關的軟體層
- MongoDB 伺服器架構,它包括記憶體、行程和檔案,這些共同作用以提供資料函式庫服務
MongoDB 檔案模型
MongoDB 是一個檔案資料函式庫。檔案資料函式庫是一類別非關聯式資料函式庫,它將資料儲存為結構化的檔案——通常採用 JavaScript 物件表示法(JSON)格式。
根據 JSON 的檔案資料函式庫(如 MongoDB)在過去十年中蓬勃發展,原因有很多。特別是,它們解決了物件導向程式設計與關聯式資料函式庫模型之間的衝突,這曾長期困擾軟體開發人員。靈活的檔案結構模型支援敏捷開發和 DevOps 正規化,並與主導的程式設計模型(尤其是現代網路應用程式的模型)緊密對齊。
JSON 與 BSON
MongoDB 使用 JavaScript 物件表示法(JSON)的變體作為其資料模型,以及其通訊協定。JSON 檔案由一套基本的結構元素構成——值、物件和陣列:
- 陣列由括在方括號(“[” 和 “]”)內並以逗號(“,”)分隔的值列表組成。
- 物件由一個或多個名稱-值對以 “名稱”:“值” 的格式組成,括在大括號(“{” 和 “}”)內並以逗號(“,”)分隔。
- 值可以是 Unicode 字串、標準格式的數字(可能包含科學記號)、布林值、陣列或物件。
由於值可以包含物件或陣列,而這些物件或陣列本身又包含值,因此 JSON 結構可以表示任意複雜和巢狀的資訊集。特別是,陣列可以用來表示重複的檔案群組,而在關聯式資料函式庫中,這需要一個單獨的表。
MongoDB 在內部以二進位 JSON(BSON)格式儲存 JSON 檔案。BSON 的設計目的是為了更緊湊、更有效地表示 JSON 資料,並對數字和其他資料型別使用更有效的編碼。例如,BSON 包含欄位長度字首,這使得掃描操作可以“跳過”元素,從而提高效率。
BSON 也提供了許多 JSON 不支援的額外資料型別。例如,JSON 中的數值在 BSON 中可以是 Double、Int、Long 或 Decimal128。其他型別如 ObjectID、Date 和 BinaryData 也經常被使用。然而,大多數時候,JSON 和 BSON 之間的差異並不重要。
集合
MongoDB 允許您將“相似”的檔案組織成集合。集合類別似於關聯式資料函式庫中的表。通常,您會將只有類別似結構或用途的檔案儲存在特定的集合中,儘管預設情況下,集合中的檔案結構並不強制執行。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title MongoDB效能調校的系統化方法
package "機器學習流程" {
package "資料處理" {
component [資料收集] as collect
component [資料清洗] as clean
component [特徵工程] as feature
}
package "模型訓練" {
component [模型選擇] as select
component [超參數調優] as tune
component [交叉驗證] as cv
}
package "評估部署" {
component [模型評估] as eval
component [模型部署] as deploy
component [監控維護] as monitor
}
}
collect --> clean : 原始資料
clean --> feature : 乾淨資料
feature --> select : 特徵向量
select --> tune : 基礎模型
tune --> cv : 最佳參數
cv --> eval : 訓練模型
eval --> deploy : 驗證模型
deploy --> monitor : 生產模型
note right of feature
特徵工程包含:
- 特徵選擇
- 特徵轉換
- 降維處理
end note
note right of eval
評估指標:
- 準確率/召回率
- F1 Score
- AUC-ROC
end note
@enduml
此圖示展示了 JSON 檔案如何被組織成集合,以及集合如何被儲存在 MongoDB 資料函式庫中。
內容解密:
此圖示用於展示 MongoDB 的檔案模型和集合的概念。JSON 檔案是 MongoDB 中的基本資料單元,而集合則是相似檔案的容器。MongoDB 資料函式庫則是這些集合的儲存所在。
結語
本章節介紹了 MongoDB 的叢集調校的重要性和系統最佳化步驟。同時,也探討了 MongoDB 的架構與核心概念,包括檔案模型、JSON 與 BSON 的區別,以及集合的概念。瞭解這些基礎知識對於後續的效能調校至關重要。