最近有個專案需要使用到 Azure Cosmos DB,並且在 POC 階段需要測試其寫入效能,當時使用相同的一包資料分別在以下環境寫入:
- 容器 A:初始建立時直接設定 10000 RU
- 容器 B:初始建立時設定 5000 RU 再手動修改至 10000 RU
表面上看起來容器 A 與容器 B 具有一樣的 10000 RU 效能,但實際的實驗結果卻是在寫入時的效能差了近一倍,原來是實體分割區在背後搞鬼。
基本概念
為了繼續討論這個問題,先快速理解幾個在 Azure Cosmos DB 中的基本概念。
- RU 要求單位:衡量 Azure Cosmos DB 的效能單位,理論上配備越高的 RU 具有越好的效能,同時也是帳單的計費單位。
| Azure Cosmos DB RU |
- 邏輯分割區:由分割區索引鍵決定,具有相同分割區索引鍵的資料會存在在同一個邏輯分割區中。
- 實體分割區:由微軟維護的底層實際運算資源,相同邏輯分割區的資料會存放在同一個實體分割區中。
| 實體分割區與邏輯分割區的一對多關係 |
問題重現
為了快速重現環境,我們使用 Azure Cosmos DB 在 Portal 中的「資料總管」,透過 UI 點擊的方式來建立單獨的資料庫與容器。首先建立稍早情境描述中的容器 A:建立名為 db_A 的資料庫,並在其中建立名為 container_A 的容器。
| 初始設定 10000 RU |
建立完成後,任意寫一筆資料進到 container_A 中。
| 任意寫一筆資料 |
這時切換到左側「監視」→「深入解析」,上方的下拉選單選到剛剛建立的資料庫 db_A,再切換到「輸送量」頁籤,就會看到以下畫面:
其中的 partitionkeyrangeid 代表的是實體分割區,嗯..有兩個實體分割區?
問題分析
Azure Cosmos DB 中的實體分割區是由微軟維護,且無法觸及到的層級,但實際上在建立容器的當下,後台會自動判斷每 6000 RU 分配一個實體分割區到這個新建立的容器中,這代表我們使用 10000 RU 建立的 container_A 會被分配到兩個實體分割區,且每個分割區會平均拿到 5000 RU 的運算效能。
回想一下前面提到的實體分割區與邏輯分割區的一對多關係,所以當資料內的分割鍵不夠分散,亦或是未經過「洗牌」,這會造成資料是同時寫入同一個邏輯分割區,但邏輯分割區只會存在在同一個實體分割區中,最終導致我們只使用 5000 RU 的運算效能在執行該次寫入任務。
最佳做法
首先應該評估未來資料增長,以計算出需要的實體分割區數量,因為每個實體分割區只能存放 50 GB 的資料量,假設評估後的總資料量是 120 GB,這時就應該規劃使用 3 個實體分割區。
再來使用 6000 * 3 的 RU 量來建立新的容器,這樣會 100% 確保 Azure 在後台分配 3 個實體分割區供我們使用。
最後在首次大量資料倒入時,將 RU 調整至 3 個實體分割區的上限,也就是 10000 * 3 RU,以求最快速的消化資料寫入。待寫入完成後,再根據後續常態的讀取頻率降低容器的 RU 量,假設平時的讀取只會使用到 3000 RU,這時 3 個實體分割區各會分到 1000 RU 的運算效能,藉此達到資源與費用成本的最大化效益。
總結
最近 AI 相關的 AP 興起,同時也帶動了 Azure Cosmos DB 的使用量,NoSQL 的特點確實也在 AP 的設計上帶來了彈性與即時性。但其中標榜的微軟幫你管實體分割區,開發人員實際上又不想去了解背後的運作邏輯,反而會造成大半的資源閒置,看來要導入一個新服務沒有想像中的簡單😤。
留言
張貼留言