整合式持續性反模式
將所有應用程式的數據放入單一數據存放區可能會損害效能,可能是因為它會導致資源爭用,或因為數據存放區不適合某些數據。
問題說明
在過去,應用程式通常會使用單一數據存放區,不論應用程式可能需要儲存的不同數據類型為何。 這通常是為了簡化應用程式設計,或符合開發小組的現有技能集。
新式雲端式系統通常具有額外的功能和非功能性需求,而且需要儲存許多異質類型的數據,例如檔、影像、快取數據、佇列訊息、應用程式記錄和遙測。 遵循傳統方法,並將所有這些資訊放入相同的數據存放區可能會損害效能,原因有兩個主要原因:
- 在相同的數據存放區中儲存和擷取大量數據可能會導致爭用,進而導致響應時間變慢和連線失敗。
- 無論選擇哪一個數據存放區,它可能不適合所有不同類型的數據,或可能無法針對應用程式執行的作業進行優化。
下列範例顯示 ASP.NET Web API 控制器,將新記錄新增至資料庫,並將結果記錄至記錄檔。 記錄會保留在與商務數據相同的資料庫中。 您可以在這裡找到完整的範例。
public class MonoController : ApiController
{
private static readonly string ProductionDb = ...;
public async Task<IHttpActionResult> PostAsync([FromBody]string value)
{
await DataAccess.InsertPurchaseOrderHeaderAsync(ProductionDb);
await DataAccess.LogAsync(ProductionDb, LogTableName);
return Ok();
}
}
產生記錄檔記錄的速率可能會影響商務作業的效能。 如果另一個元件,例如應用程式進程監視器,定期讀取和處理記錄數據,這也可能會影響商務作業。
如何修正問題
根據數據的使用來分隔數據。 針對每個數據集,選取最符合該數據集使用方式的數據存放區。 在上述範例中,應用程式應該記錄到與保存商務數據之資料庫的個別存放區:
public class PolyController : ApiController
{
private static readonly string ProductionDb = ...;
private static readonly string LogDb = ...;
public async Task<IHttpActionResult> PostAsync([FromBody]string value)
{
await DataAccess.InsertPurchaseOrderHeaderAsync(ProductionDb);
// Log to a different data store.
await DataAccess.LogAsync(LogDb, LogTableName);
return Ok();
}
}
考量
使用數據的方式和存取方式來分隔數據。 例如,請勿將記錄資訊和商務數據儲存在相同的數據存放區中。 這些類型的數據具有截然不同的需求和存取模式。 記錄記錄本質上是循序的,而商務數據更可能需要隨機存取,而且通常是關係型。
請考慮每種數據類型的數據存取模式。 例如,將格式化的報表和文件儲存在文件資料庫中,例如 Azure Cosmos DB,但使用 Azure Cache for Redis 快取暫存數據。
如果您遵循此指引,但仍達到資料庫的限制,您可能需要相應增加資料庫。 也請考慮水平調整,並將負載分割到資料庫伺服器。 不過,數據分割可能需要重新設計應用程式。 如需詳細資訊,請參閱 數據分割。
如何偵測問題
系統可能會大幅降低速度,最終會失敗,因為系統用盡了資料庫連線等資源。
您可以執行下列步驟來協助識別原因。
- 檢測系統以記錄關鍵效能統計數據。 擷取每個作業的計時資訊,以及應用程式讀取和寫入數據的點。
- 可能的話,請監視在生產環境中執行幾天的系統,以取得系統使用方式的實際檢視。 如果無法執行此動作,請以實際數量執行虛擬使用者執行一系列作業的腳本式負載測試。
- 使用遙測數據來識別效能不佳的期間。
- 識別在這些期間存取哪些數據存放區。
- 識別可能發生爭用的數據記憶體資源。
診斷範例
下列各節會將這些步驟套用至稍早所述的範例應用程式。
檢測和監視系統
下圖顯示稍早所述的範例應用程式負載測試結果。 測試使用了最多 1000 個並行使用者的步驟負載。
當負載增加至 700 位使用者時,輸送量也會增加。 但此時,輸送量層級會關閉,而且系統似乎在其最大容量上執行。 平均回應隨著使用者負載逐漸增加,顯示系統無法跟上需求。
識別效能不佳的期間
如果您要監視生產系統,您可能會注意到模式。 例如,回應時間可能會每天大幅下降。 這可能是由一般工作負載或排程的批次作業所造成,或只是因為系統在特定時間有更多的使用者。 您應該專注於這些事件的遙測數據。
尋找增加回應時間與資料庫活動增加或共用資源的 I/O 之間的相互關聯。 如果有相互關聯,表示資料庫可能是瓶頸。
識別在這些期間存取哪些數據存放區
下一個圖表顯示負載測試期間資料庫輸送量單位 (DTU) 的使用率。 (DTU 是可用容量的量值,而且是 CPU 使用率、記憶體配置、I/O 速率的組合。DTU 使用率迅速達到100%。 這是大致上一個圖表中輸送量尖峰的點。 資料庫使用率仍然很高,直到測試完成為止。 結尾略有下降,可能是因為節流、資料庫連線競爭或其他因素所造成。
檢查數據存放區的遙測
檢測數據存放區以擷取活動的低階詳細數據。 在範例應用程式中,數據存取統計數據會顯示針對 PurchaseOrderHeader
數據表和 MonoLog
數據表執行的大量插入作業。
識別資源爭用
此時,您可以檢閱原始程式碼,專注於應用程式存取競爭資源的位置。 尋找下列情況:
- 以邏輯方式分隔寫入相同存放區的數據。 記錄、報表和佇列訊息等數據不應保留在與商務資訊相同的資料庫中。
- 數據存放區選擇與數據類型不符,例如關係資料庫中的大型 Blob 或 XML 檔。
- 共用相同存放區具有明顯不同使用模式的數據,例如使用低寫入/高讀取數據儲存的高寫入/低讀取數據。
實作解決方案並驗證結果
應用程式已變更為將記錄寫入個別的數據存放區。 以下是負載測試結果:
輸送量模式與先前的圖表類似,但效能尖峰的時間點大約是每秒 500 個要求。 平均回應時間略低。 不過,這些統計數據不會說明完整的故事。 商務資料庫的遙測顯示 DTU 使用率尖峰約為 75%,而不是 100%。
同樣地,記錄資料庫的最大 DTU 使用率只會達到大約 70%。 資料庫不再是系統效能的限制因素。