MongoDB 副本集的讀寫效能最佳化對於應用程式至關重要。合理組態讀取偏好能有效降低主節點負載,提升讀取吞吐量。藉由 maxStalenessSeconds 引數,開發者可以根據業務需求平衡資料一致性和讀取效能。此外,標籤集的運用能更精細地控制讀取請求的路由,實作讀取負載平衡和特定資料中心的讀取需求。寫入關注級別的選擇則需考量資料安全性和寫入效能之間的平衡。對於全文檢索,Atlas Search 提供了多種分析器,需根據實際場景選擇合適的分析器以提升搜尋效率。最後,當單一副本集無法滿足效能需求時,分片技術能有效分散資料和負載,實作水平擴充套件。
MongoDB 副本集讀寫效能最佳化
在 MongoDB 副本集中,讀寫效能的最佳化對於整體系統的效能至關重要。預設情況下,所有讀取操作都被導向至主節點(Primary),但我們可以透過設定讀取偏好(Read Preference)來將讀取請求導向至副本文點(Secondary),從而提高讀取效能。
使用讀取偏好
讀取偏好允許我們控制 MongoDB 驅動程式將讀取請求導向至哪個節點。主要有以下幾種讀取偏好設定:
- primary:所有讀取操作都被導向至主節點,這是預設設定。
- primaryPreferred:優先將讀取操作導向至主節點,如果主節點不可用,則導向至副本文點。
- secondary:將讀取操作導向至副本文點。
- secondaryPreferred:優先將讀取操作導向至副本文點,如果沒有可用的副本文點,則導向至主節點。
- nearest:將讀取操作導向至網路延遲最低的節點,無論是主節點還是副本文點。
圖表說明:不同讀取偏好對讀取效能的影響
@startuml
note
無法自動轉換的 Plantuml 圖表
請手動檢查和調整
@enduml此圖示展示了不同讀取偏好設定下,從不同位置發出的查詢所耗費的時間。可以看到,使用 nearest 讀取偏好總是能夠獲得最佳的讀取效能。
設定讀取偏好
讀取偏好可以在連線 MongoDB 時設定,也可以在特定的查詢陳述式中設定。
在連線 URI 中設定
mongodb://n1,n2,n3/?replicaSet=rs1&readPreference=secondary
在查詢陳述式中設定(以 Node.js 為例)
const client = await mongo.MongoClient.connect(myMongoDBURI);
const collection = client.db('MongoDBTuningBook').collection('customers');
const options = {'readPreference': mongo.ReadPreference.NEAREST};
await collection.find({}, options).forEach((customer) => {
count++;
});
使用 maxStalenessSeconds 引數
maxStalenessSeconds 引數可以用於控制允許的資料延遲。當選擇副本文點時,MongoDB 驅動程式只會考慮那些資料時間戳在 maxStalenessSeconds 秒內的主節點資料。最小值為 90 秒。
例如,以下 URI 指定了優先選擇副本文點,但只會選擇那些資料時間戳在 5 分鐘(300 秒)內的主節點資料的副本文點:
mongodb://n1,n2,n3/?replicaSet=rs1&readPreference=secondary&maxStalenessSeconds=300
程式碼範例與內容解密
以下是一個使用 maxStalenessSeconds 的程式碼範例:
const uri = "mongodb://n1,n2,n3/?replicaSet=rs1&readPreference=secondary&maxStalenessSeconds=300";
const client = new MongoClient(uri);
await client.connect();
const database = client.db('myDatabase');
const collection = database.collection('myCollection');
const query = { /* your query */ };
const options = { /* your options */ };
const cursor = collection.find(query, options);
await cursor.forEach(doc => console.log(doc));
await client.close();
內容解密:
maxStalenessSeconds引數的作用:此引數確保了當使用副本文點讀取資料時,資料的最新程度不會太舊,從而避免了因讀取過時資料而導致的錯誤。readPreference設定為secondary:這表示優先從副本文點讀取資料,如果沒有可用的副本文點,才會從主節點讀取。MongoClient連線字串的組態:正確組態連線字串中的replicaSet、readPreference和maxStalenessSeconds引數,可以靈活控制 MongoDB 的讀取行為。
副本集與標籤集的最佳實踐
在 MongoDB 的副本集架構中,標籤集(Tag Sets)提供了一種靈活的方式來控制讀取偏好(Read Preference),將查詢請求導向特定的次要節點或節點群。這種機制不僅能最佳化讀取效能,還能根據不同節點的角色或地理位置進行工作負載的分佈。
組態標籤集
首先,我們需要為副本集中的各個節點設定標籤。假設我們的副本集包含三個節點,分別位於香港、東京和韓國,我們可以按以下方式組態:
mongo> conf = rs.conf();
mongo> conf.members.forEach((m)=>{print(m.host);});
mongors01.eastasia.cloudapp.azure.com:27017
mongors02.japaneast.cloudapp.azure.com:27017
mongors03.koreacentral.cloudapp.azure.com:27017
mongo> conf.members[0].tags={"location":"HongKong","role": "prod" };
mongo> conf.members[1].tags={"location":"Tokyo","role":"BI" };
mongo> conf.members[2].tags={"location":"Korea","role": "prod" };
mongo> rs.reconfig(conf);
{
"ok": 1,
...
}
組態解說:
rs.conf():取得當前副本集的組態。conf.members.forEach((m)=>{print(m.host);}):列印所有成員的主機位址。- 為每個成員設定
tags屬性,包含location和role標籤,用於區分節點的位置和角色。 rs.reconfig(conf):重新組態副本集,使標籤生效。
使用標籤集進行讀取操作
組態完成後,我們可以根據標籤將讀取請求導向特定的節點。例如,將查詢導向具有 prod 角色的節點:
db.customers.find({ Phone: 40367898 }).readPref('secondaryPreferred', [{ role: 'prod' }]);
讀取偏好解說:
readPref('secondaryPreferred', [{ role: 'prod' }]):優先從具有prod角色的次要節點讀取資料。- 這種方式適合將特定型別的查詢導向特定的節點,例如將分析型查詢導向專門的 BI 節點。
工作負載分佈
利用標籤集,我們還可以將不同集合的查詢分散到不同的節點,從而提升整體效能。例如,將三個集合的查詢分別導向香港、韓國和東京的節點:
db.getMongo().setReadPref('secondaryPreferred', [{ "location": "HongKong" }]);
db.iotData1.aggregate(pipeline, { allowDiskUse: true });
工作負載分佈解說:
setReadPref:為當前資料函式庫連線設定讀取偏好,將查詢導向香港節點。db.iotData1.aggregate:執行聚合查詢,並允許使用磁碟空間處理大資料集。
寫入關注(Write Concern)
寫入關註定義了 MongoDB 在確認寫入操作完成前需要滿足的條件,包括寫入的節點數量、日誌寫入要求和超時設定。
寫入關注引數:
w: 控制需要多少個節點接收寫入操作後才算完成,可設為數字或"majority"。j: 是否要求寫入操作必須寫入日誌(journal)後才算完成。wtimeout: 設定寫入關注的超時時間。
日誌寫入與效能考量
當 j:false 時,寫入操作在被 mongod 接收後即視為完成;而 j:true 則要求寫入操作必須寫入預寫日誌(write-ahead journal)。雖然停用日誌寫入可能提升效能,但在某些情況下會增加資料丟失的風險。
寫入關注的 w 選項
w 選項決定了寫入操作需要傳播到多少個節點才算完成。預設值為 1,即只需主節點接收寫入。設定為 "majority" 可以確保大多數節點接收到寫入,從而提高資料安全性。
圖示解析:
圖 13-3 展示了 {w:2,j:true} 的寫入關注流程:
- 主節點接收寫入並寫入日誌。
- 透過複製將寫入操作傳播到次要節點。
- 次要節點將寫入操作寫入其日誌後,寫入操作才算完成。
MongoDB 寫入關注(Write Concern)對效能的影響
在 MongoDB 中,寫入關注(Write Concern)是確保資料寫入的安全性和可靠性的機制。寫入關注的級別越高,資料寫入的安全性越高,但效能也會受到影響。
寫入關注級別與效能
根據圖 13-4 的測試結果,當寫入 50,000 筆資料時,不同的寫入關注級別對效能的影響非常顯著。結果顯示,w:0 的寫入關注級別提供了最佳的效能,但也意味著資料寫入的可靠性最低。
內容解密:
w:0:表示不需要確認寫入是否成功,這種模式下效能最佳,但資料可能會遺失。w:1、w:2、w:3:表示需要確認寫入是否成功,分別對應不同的節點數量,這些模式下效能會降低,但資料可靠性提高。
寫入關注與次要讀取(Secondary Reads)
雖然提高寫入關注級別會降低修改作業的效能,但對於讀取密集型的應用程式來說,可能會有正面的影響。如果寫入關注級別設定為將資料寫入叢集中的所有成員,那麼次要讀取(Secondary Reads)將始終傳回正確的資料。
內容解密:
- 當寫入關注級別設定為
w:n(n 為叢集中的節點數量)時,次要讀取將傳回最新的資料。 - 但如果叢集中有節點故障,寫入作業可能會失敗。
MongoDB Atlas 與其功能
MongoDB Atlas 是 MongoDB 提供的完全託管的資料函式庫服務。使用 Atlas,可以輕鬆建立和組態 MongoDB 複本集(Replica Sets)和分片叢集(Sharded Clusters),無需自行組態硬體或虛擬機器。
Atlas Search 功能
Atlas Search 是根據 Apache Lucene 的全文檢索功能,提供了比 MongoDB 內建的文字索引更強大的搜尋能力。Atlas Search 提供了多種分析器(Analyzer),可以根據不同的需求選擇適合的分析器。
Atlas Search 分析器型別
- Standard Analyzer:將所有文字轉換為小寫,忽略標點符號,並正確處理特殊符號和縮寫。
- Simple Analyzer:類別似 Standard Analyzer,但處理「詞彙」(word)的邏輯較簡單。
- Whitespace Analyzer:僅根據空白字元分割文字,不進行其他處理。
- Keyword Analyzer:將整個欄位視為一個單元,需要完全匹配才能傳回結果。
- Language Analyzer:針對不同語言提供預設的分析器,能夠根據語言特性進行索引。
內容解密:
- 選擇適合的分析器可以改善搜尋結果的相關性,但也可能影響查詢效能。
- 不同的欄位可能需要不同的分析器,例如描述欄位可能適合使用 Language Analyzer,而屬性型別欄位則適合使用 Keyword Analyzer。
圖表分析
圖 13-5 比較了不同分析器對索引大小的影響。結果顯示,不同分析器對索引大小的影響差異很大。
內容解密:
- 索引大小會影響搜尋效能和儲存空間的需求。
- 選擇分析器時需要考慮資料特性和查詢需求。
綜上所述,MongoDB 的寫入關注級別和 Atlas Search 功能都對效能和資料可靠性有重要影響。選擇合適的寫入關注級別和 Atlas Search 分析器,可以在保證資料可靠性的同時,最佳化應用程式的效能。
Atlas Search 分析器效能比較與資料湖應用
在建立 Atlas Search 索引時,選擇適當的分析器(Analyzer)對於搜尋效能和結果準確性至關重要。不同的分析器會對索引大小和查詢時間產生不同的影響。
索引大小與分析器型別的關係
從圖 13-5 中可以看出,不同的分析器型別對索引大小的影響在較小的文字欄位中差異不大,但在較大的文字欄位中則會有顯著的不同。標準分析器(Standard Analyzer)、簡單分析器(Simple Analyzer)、空白分析器(Whitespace Analyzer)、關鍵字分析器(Keyword Analyzer)和語言分析器(Language Analyzer)在索引大小上的表現各不相同。
索引大小比較
| 分析器型別 | 小欄位索引大小 | 大欄位索引大小 |
|---|---|---|
| 標準分析器 | 0.4595 | 2.97 |
| 簡單分析器 | 0.4002 | 5.52 |
| 空白分析器 | 0.3676 | 6.10 |
| 關鍵字分析器 | 0.5119 | 6.10 |
| 語言分析器 | 0.4053 | 5.29 |
查詢時間與分析器型別的關係
圖 13-6 展示了不同分析器型別對查詢時間的影響。關鍵字分析器的查詢時間最短,但其搜尋結果可能不如其他分析器準確。
查詢時間比較
| 分析器型別 | 查詢時間(秒) |
|---|---|
| 標準分析器 | 2.13 |
| 簡單分析器 | 2.50 |
| 空白分析器 | 2.10 |
| 關鍵字分析器 | 1.99 |
| 語言分析器 | 2.11 |
分析器型別的選擇
雖然關鍵字分析器的查詢時間最短,但其搜尋結果可能不佳。標準分析器在查詢時間和結果準確性之間取得了良好的平衡,因此通常是個不錯的選擇。
Atlas Data Lake 的應用
Atlas Data Lake 是 MongoDB 提供的一種用於查詢 Amazon S3 儲存桶中資料的工具。它允許使用者使用 MongoDB 查詢語言來查詢外部資料。雖然 Data Lake 看起來像一個普通的 MongoDB 資料函式庫,但它有一些限制,例如缺乏索引。
資料湖的限制與最佳化
由於 Data Lake 缺乏索引,查詢可能會變慢。為了最佳化查詢效能,可以將資料分成多個檔案,並使用檔名來反映關鍵屬性值,從而限制查詢的檔案範圍。
// 定義 Data Lake 中的 customers 集合
customers: [
{
definition: '/customers/{customerId string}',
store: 's3store'
}
]
程式碼解析
上述程式碼定義了 Data Lake 中的 customers 集合,將資料儲存在不同的檔案中,每個檔案對應一個客戶,檔名包含客戶 ID。這種設計可以最佳化查詢效能,減少查詢所需的檔案數量。
使用 Plantuml 圖表展示資料湖架構
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title 使用 Plantuml 圖表展示資料湖架構
rectangle "資料儲存" as node1
rectangle "查詢介面" as node2
rectangle "查詢結果" as node3
node1 --> node2
node2 --> node3
@enduml此圖示展示了 Atlas Data Lake 的架構,資料儲存在 Amazon S3 中,透過 Data Lake 提供查詢介面,使用 MongoDB 查詢語言進行查詢,並將結果傳回給應用程式。
分片技術在MongoDB中的應用與效能最佳化
在前一章中,我們探討了最常見的MongoDB佈署組態:複製集。複製集對於需要高用性的現代應用程式至關重要,因為單一的MongoDB例項無法滿足這些需求。正如我們所見,複製集可以透過次要寫入來進行有限的讀取擴充套件。但是,對於大型應用程式,特別是寫入工作負載超過單個叢集能力的情況,則需要佈署分片叢集。
分片基礎
我們在第2章中介紹了分片技術。在分片資料函式庫叢集中,選定的集合會被分散到多個資料函式庫例項中。每個分割槽被稱為一個「分片」。這種分割槽是根據分片鍵值進行的。
雖然複製集旨在提供高用性,但分片技術旨在提供更大的可擴充套件性。當工作負載(尤其是寫入工作負載)超過伺服器的容量時,分片提供了一種將工作負載分散到多個節點的方法。
資料湖中的檔案結構最佳化
在Atlas資料湖中,檔案結構的設計對於查詢效能有著重要的影響。透過將資料分割成多個檔案,並根據查詢鍵值命名檔案,可以顯著提高查詢效能。例如,將客戶資料分割成多個JSON檔案,每個檔案名對應一個客戶ID(如/customers/1234.json),這樣在查詢特定客戶資料時,資料湖只需掃描相關的檔案,而不是整個目錄。
程式碼範例:定義資料湖中的集合
{
"name": "customersNew",
"source": {
"bucket": "datalake02",
"path": "/customers/"
},
"partition": {
"fields": [
{
"name": "customerId",
"path": "$.customerId"
}
]
},
"storage": [
{
"store": "s3store"
}
]
}
內容解密:
- 定義集合名稱:
customersNew是新集合的名稱。 - 來源設定:指定資料來源的儲存桶和路徑。
- 分割欄位:根據
customerId欄位對資料進行分割。 - 儲存設定:指定使用的儲存型別為
s3store。
透過這種方式定義集合,可以實作根據客戶ID進行高效查詢。
分片對效能的影響
分片技術對於提高MongoDB的可擴充套件性和效能至關重要。正確的分片策略可以顯著提高寫入效能和查詢效能。然而,分片也帶來了一些挑戰,如跨分片查詢的複雜性和維護成本。