[Day 16] 先別急著 Scaling

erichung0404
2024-08-16 18:53:50

就像上篇說的一樣, 雖然 水平擴展 是一個強大的擴展方式, 但他也會造成系統維護很大的困難

所以我們要先確認 "真的需要水平擴展嗎"?

如果我們的系統能夠用教科書式的架構, 支援幾萬 QPS 和 幾百萬 Concurrent Request (並行請求)
但是實際上只有十位數 QPS, 幾百 Concurrent Request
這樣不僅浪費資源和金錢, 也無謂的增加了系統的複雜度
所以先了解當前系統的 Performance Bottleneck (效能瓶頸) 並針對性的優化是很重要的

本篇先來介紹簡單的評估步驟

1. 找出效能瓶頸

2. 評估預期負載

3. 資料特性

4. 評估成本

5. Scaling

找出效能瓶頸

假設使用者回報 "登入時間變長", 並假設我們所有的服務都只有一個節點
那麼我們可以從牽涉到 "使用者登入" 的服務開始查起

可以看到使用者登入的流程是

1. 使用者 發送請求給 Public API

2. Public API 發給 Internal API

3. Internal API 檢查使用者是否已登入, 沒有則發給 驗證服務

4. 驗證服務 通過後使用者即可登入

所以牽涉到 3 個節點: Public API, Internal API, 驗證服務
可以分別檢查這幾個服務處理使用者登入花費的時間

另一個可能, 也是當前系統一個潛在的 Bottleneck: Internal API 伺服器負擔太重
由於 Internal API 會收到 登入請求, 支付請求, 通知服務, 存取 Database 的請求等
不同請求所花費的資源和時間不同, 全部都由同一個伺服器處理 "有可能" 影響到 登入請求 的時間

所以一種方式是 "將登入的 API 伺服器獨立出來"

評估預期負載

(以下僅為可能的評估方向, 實際情況若有監控系統則以指標為主)

接續上面範例, 我們需要了解每個服務大概的請求數量
以登入服務來說, 如果不考慮 timeout 機制, 通常使用者 "不會頻繁登出"
所以驗證服務本身不太可能是 Bottleneck 的原因

根據 Day 12, 13 天的介紹, 支付的請求也不會消耗太多資源
雖然請求數量會比驗證服務多, 但不太會是原因, 通知服務也是同理

所以最有可能的是 Database 請求, 視我們服務的複雜程度, 如果沒有做好回覆的長度限制如 Pagination
就有可能佔用大量記憶體
且建立 Database 連線也很吃資源, 如果沒有 Connection Pool (連線池) 也有可能造成 Resource Outage
等等等等

通常除了應用本身以外, 效能瓶頸大多會體現在 Database 上囧

資料特性

以 RDBMS 為例, 另一種可能是我們將不同特性的資料塞在同一張表, 比如 Read-heavy 的資料和 Write-heavy 的資料放在同一張表
由於寫入資料時某些 Database 會上 表鎖 (Table Lock) 或 列鎖 (Row Lock), 也會造成性能下降
(之後的 Challenge 主題介紹)

所以最好是將 讀寫分離

Scaling

如果我們已經找到了造成 Bottleneck 的服務, 並且簡單的優化並無法解決當前的效能瓶頸
或是想要提高系統的 Availability

最後決定透過水平擴展解決, 那就繼續看下去吧!

Reference

MySQL的Lock是什麼? Table Lock與Row Lock有哪些不同?