【從一台 Server 到分散式架構】第 02 篇:Server CPU 爆了——認識負載與瓶頸
上一篇講了小明他們的線上課程平台,在用戶還不多的時候,一個前端、一個後端、一個資料庫就跑得很順。但故事不會停在這裡。
使用者慢慢變多了。同時上線的從幾十人變成幾百人、上千人,大家在看影片、刷課程列表、點首頁。然後小明他們開始發現:首頁變慢了,有時候還會出現 504,後台一看,資料庫的 CPU 飆得很高。
這一篇不談解法(那是後面幾篇的事),只談兩件事:什麼叫負載、什麼叫瓶頸?以及,怎麼從「變慢、超時、錯誤變多」裡感覺到系統需要改變,並且初步判斷——問題比較可能出在後端,還是出在資料庫?這會決定後面要先優化哪一層。
什麼叫負載?什麼叫瓶頸?
負載(load)很直白:就是系統正在承受的「工作量」。以課程平台來說,同一時間有多少人在用、發了多少請求、資料庫被查了多少次,都是負載。使用者變多、請求變多,負載就上去。
瓶頸(bottleneck)就是:在整條請求的路徑上,最先撐不住的那一環。可能是後端的 CPU 或記憶體不夠、可能是資料庫查詢太慢或連線數爆掉、也可能是網路或磁碟 I/O。瓶頸卡住了,後面的請求就排隊、變慢,甚至超時、噴錯。
所以當小明他們發現「首頁變慢、有時 504」的時候,其實就是在經歷:負載變高,而某一個地方變成了瓶頸。接下來要做的,就是找出瓶頸在哪一層——是後端在算太多東西,還是資料庫查詢太重?
怎麼「感覺」到系統需要改變?
一開始通常會先從使用者的體感或錯誤訊息發現問題,沒有錯。大致有幾種:
- 變慢:頁面載入變久、按下去要等好幾秒才有反應。代表請求從發出到回傳的時間變長了,也就是延遲(latency)變高。
- 超時:例如出現 504 Gateway Timeout,代表請求等太久、伺服器沒在時間內回傳,被判定超時。這常常是後端或資料庫已經忙不過來、請求在排隊的結果。
- 錯誤變多:除了 504,可能還有 500、連線失敗、部分功能時好時壞。代表系統在高負載下開始不穩定,錯誤率(error rate)上升。
這些都是「系統需要改變」的訊號。小明他們不需要先背一堆指標,只要能夠從變慢、超時、錯誤變多裡意識到「負載上來了、有地方變成瓶頸了」,就足夠當作起點。
等到之後有監控、有數據,這些體感會對應到可以量化的指標:延遲會用毫秒(ms)或 P95、P99 回應時間來看;流量會用每秒請求數(QPS 或 RPS)來看;錯誤率會用失敗請求數/總請求數來看。監控篇會再細講;這裡先建立「變慢、超時、錯誤變多」就是在反映這三類問題的直覺。
瓶頸在後端,還是在資料庫?
同一套症狀(變慢、504),可能來自不同原因。先從情境上分兩種:
可能是後端:例如後端程式在處理每一筆請求時做了很重的運算、呼叫太多外部 API、或記憶體用太多導致 swap。這時候後端那台機器的 CPU 或記憶體 usage 會很高,而資料庫可能還算正常。
可能是資料庫:例如大家瘋狂查「課程列表」「熱門排行」,同一個查詢被重複打、又沒有索引或查詢寫得不好,導致資料庫 CPU 飆高、查詢變慢。後端其實只是在等資料庫回傳,等久了就超時,所以使用者看到 504,但真正的瓶頸是 DB。
要判斷是哪一種,就要看誰在吃資源。這裡有個前提:後端和資料庫可能是同一台機器、同一台機器跑多個 Docker container、或分開在不同機器。情境不同,看法稍微不一樣。
- 後端和 DB 在同一台機器:看的是同一台機器的 CPU、記憶體。用
top或htop看是哪一個 process 在吃 CPU 或記憶體——若是後端程式(例如 Node、Python、Java process)長期佔滿,瓶頸多半在後端;若是 DB 的 process(例如 MySQL、PostgreSQL)飆高,瓶頸在資料庫。若跑 Docker,可以看每個 container 的資源(docker stats或監控工具),一樣是看誰吃滿。 - 後端和 DB 在不同機器:就分別看兩台機器的 CPU、記憶體。哪一台先吃滿,那一層就比較可能是瓶頸。
- 不論是否同機,資料庫這層還可以這樣看:許多資料庫會把「執行時間超過某個門檻」的查詢記下來,這就是慢查詢 log(slow query log)。若裡面出現大量耗時的 SELECT(例如查課程列表、熱門排行),代表瓶頸在查詢。實務上:MySQL 可在設定檔開啟
slow_query_log、指定slow_query_log_file路徑,門檻用long_query_time(秒);PostgreSQL 則用log_min_duration_statement設定門檻(毫秒),慢於此的 SQL 會寫進一般 log。詳細可查各資料庫文件。另外,若 連線數(connection pool)被佔滿、新請求連不上 DB,也會表現成後端等 DB 等到超時,但本質是 DB 的連線或處理能力不足。
假設小明他們用 top 或 htop 一看,發現吃滿 CPU 的是資料庫的 process,或打開慢查詢 log 發現一堆查「課程列表」「熱門排行」的 SELECT 都跑好幾秒,那就是很典型的瓶頸在資料庫:這類讀取被大量請求,資料庫扛不住。能分辨瓶頸在後端還是 DB,後面要先做索引與查詢優化、讀寫分離、快取,還是先優化後端或擴充,方向才會對。
小明他們現在遇到的狀況
整理一下:課程平台同時上線的人變多了,首頁變慢、有時 504,後台一看資料庫 CPU 飆高。這代表負載上來了,而目前的瓶頸比較像在資料庫——查詢太多或太慢,拖累了整條請求。
當然實務上可能會是後端和資料庫都有壓力,但先能判斷「這一波主要是誰在爆」,就夠了。下一篇會談:當單機或單一資料庫已經撐不住,要先「把機器升級」(垂直擴充),還是「多加幾台機器」(水平擴充),以及水平擴充時前面要擺誰來分流。我們下一篇見。