一、一場全台灣都記得的當機:2015 江蕙告別演唱會售票之亂
2015 年 1 月 2 日,江蕙宣布唱完《祝福》演唱會後封麥。1 月 5 日中午 12 點,首波台北四場、高雄兩場約 6 萬張門票開賣——面對的是整個世代的歌迷。
開賣當天,寬宏售票網站一早就當機、癱瘓一整天,中午 12 點正式開賣時,多數人根本連不上網站。流量還沿著整條購票鏈路蔓延:7-11 的 ibon 持續顯示「流量管制中」,全家 FamiPort 一直停在「網頁處理中,請稍候」,四大超商通路全數卡住,最後反而是到現場排隊的人比較買得到票。接下來幾天風波不斷:約 800 名領了號碼牌的歌迷最終買不到票、組成自救會抗議,寬宏總經理出面說明時被潑咖啡,江蕙凌晨在臉書道歉,最後以宣布加場收場。
這個故事還有一個十年後的續集,而且對學效能測試的人特別有意義。2025 年江蕙復出開唱,售票方式徹底改變:改採「實名登記抽選制」,開放三天登記後抽籤。登記票數超過 260 萬張,門票只有 20 萬張,中籤率僅 7.6%——需求比當年更兇猛,但這次系統沒有癱瘓。原因值得細品:瞬間湧入的「搶」,被重新設計成分散三天的「登記」。與其硬撐流量的尖峰,不如改變流量的形狀——這是面對效能極限的另一種解法。
(事件經過依中央社、公視 2015 年 1 月報導;2025 年登記數字為寬宏售票系統公告、經多家媒體轉載,屬業者公告數據。)
回到 2015 年當機的那一天:購票網站的「功能」其實都是對的——查場次、選座位、結帳,每個流程都存在,前一天也都運作正常。垮掉的是另一件事:系統撐不撐得住全台灣同時湧進來。順帶一提,ibon 上那行「流量管制中」,正是工程團隊在尖峰下啟動的保護機制——這類機制該怎麼設計、上線前怎麼驗證有效,就是效能測試的守備範圍。這正是接下來三個問題要處理的事。
二、功能測試通過,不代表系統撐得住
功能測試回答「對不對」:輸入正確的折扣碼,金額有沒有算對。效能測試回答「撐不撐得住」:一萬個人同時輸入折扣碼,系統是不是還能在合理時間內把每一筆都算對。兩個問題都重要,但驗證方法完全不同——後者無法靠人手動測出來,因為你找不到五千個同事幫你同時按結帳。

圖 1:功能測試驗證「一個人操作正確」,真實上線面對的是「一群人同時操作」
這就是效能測試工具存在的理由:用程式模擬成百上千個使用者,代替那五千個你找不到的同事。本系列使用的 k6 就是這樣的工具,而 Claude Code 會負責幫不會寫程式的你產生和解釋測試腳本。
三、效能測試要回答的三個問題
效能測試不是「跑個壓力測試看看會不會掛」這麼籠統。它有三個明確要回答的問題,之後 30 天的所有技術,都是圍繞這三個問題展開:

圖 2:容量、速度、穩定——效能測試的三個核心問題
• 撐得住多少人(容量):系統在多少同時使用者之下還能正常服務?超過多少人開始出錯?
• 回應有多快(速度):不只看平均,更要看「最慢的那批人」等了多久。
• 撐得了多久(穩定):短時間沒事,連續跑八小時後會不會越來越慢、最後耗盡資源?
給 RD 的補充:這三個問題分別對應容量規劃(capacity planning)、延遲分佈(latency percentiles)與資源洩漏(resource leak)三類工程議題。給 QA 的補充:你不需要會修這三類問題,但你會是第一個用數據發現它們的人。
四、人越多越慢,而且不是等比例變慢
很多人的直覺是:使用者變成兩倍,系統就慢兩倍。真實系統不是這樣。負載低的時候,多一些人幾乎感覺不到;但超過某個臨界點後,回應時間會急遽惡化,最後直接崩潰——就像高速公路,車流到八成之前都還順暢,再多一點點就瞬間變成停車場。

圖 3:回應時間對負載的典型曲線——舒適區、警戒區、崩潰區
效能測試的重要任務之一,就是找出你的系統的臨界點在哪裡,讓團隊在上線前就知道「我們的極限大約是多少人」,而不是讓行銷活動當晚才知道。
五、動手做:15 分鐘,親手驗證這些觀念
光看觀念不會留下記憶,動手跑過才會。接下來你會安裝 k6、對官方練習站跑兩次測試(先當 1 個人、再當 20 個人),然後比較兩份結果。練習目標是 Grafana 官方公開的示範網站 QuickPizza(https://quickpizza.grafana.com)——一個披薩推薦網站,官方明確提供給大家練習 k6 使用,所以對它做小流量測試是合法且被歡迎的。

圖 4:今天的動手做流程——五個步驟,全程約 15 分鐘
步驟 1:安裝 k6(只裝這一個)
k6 是單一執行檔,沒有複雜的相依套件。依你的作業系統擇一執行:
Windows(在「命令提示字元」或 PowerShell 執行):
winget install k6 --source winget
macOS(在「終端機」執行,需已安裝 Homebrew):
brew install k6
安裝完成後,關掉視窗重開一個,輸入以下指令驗證:
k6 version
看到類似「k6 v1.x.x」的版本資訊就代表成功。如果出現「找不到指令」,最常見的原因是沒有重開視窗——先重開再試一次。
步驟 2:建立測試腳本
在桌面或任何資料夾建立一個純文字檔,命名為 first-test.js(用記事本或任何編輯器都可以),把下面的內容完整貼進去。每一行在做什麼,註解都寫在旁邊——今天先看懂註解就好,程式細節之後會由 Claude Code 幫你處理:
import http from 'k6/http';
import { check, sleep } from 'k6';
// ── 測試設定 ──────────────────────────────
// vus:同時模擬的「虛擬使用者」人數
// duration:整個測試要持續跑多久
export const options = {
vus: 1, // 先當 1 個人
duration: '30s', // 跑 30 秒
};
// ── 每個虛擬使用者重複做的事 ──────────────
export default function () {
// 對練習站首頁發出 GET 請求(等同瀏覽器打開網頁)
const res = http.get('https://quickpizza.grafana.com/');
// 檢查:伺服器回應的狀態碼是否為 200(代表成功)
check(res, {
'狀態碼是 200': (r) => r.status === 200,
});
// 停 1 秒再做下一輪,模擬真人操作的間隔
sleep(1);
}
白話翻譯整個腳本:「扮演 1 個使用者,連續 30 秒重複做這件事:打開 QuickPizza 首頁 → 確認有成功打開 → 休息 1 秒 → 再來一次。」就這麼簡單。
步驟 3:第一次執行——先當 1 個人
打開命令提示字元或終端機,切換到腳本所在的資料夾(例如桌面),執行:
cd Desktop
k6 run first-test.js
30 秒後測試結束,畫面會出現一大片統計數字。今天只需要看三個地方,並把數字抄在紙上或筆記裡(等一下要比較):
• checks_succeeded:應該是 100%——代表每次都成功打開網頁
• http_req_duration 那一行的 avg(平均回應時間)與 p(95)
• http_reqs:30 秒內總共發出了幾個請求
步驟 4:第二次執行——變成 20 個人
不用改腳本。k6 允許在指令上直接覆寫人數與時間,這樣跑:
k6 run --vus 20 --duration 30s first-test.js
--vus 20 的意思是把虛擬使用者改成 20 個。現在有 20 個「你」同時在打開網頁。跑完後,把同樣三個數字抄下來。
步驟 5:比較兩份結果——這就是你的第一次效能分析
把兩次的數字填進下表:
你大概會看到什麼(誠實版):
總請求數會接近 20 倍——20 個人各自不停地發請求,總量當然大幅增加。但回應時間可能幾乎沒變慢,甚至兩次差不多。這不是你做錯了,而是一個重要的觀念:QuickPizza 是官方營運的網站,主機非常充足,我們 20 個人的小流量對它來說連暖身都算不上——它還穩穩待在圖 3 的舒適區裡。
這正是今天最值得帶走的一課:「看不到變慢」也是一種有意義的測試結果,它告訴你目前的負載遠低於系統容量。真的要看到圖 3 的警戒區與崩潰區,需要更大的負載或更小的系統,那是之後的課題。今天你已經完成更重要的事:親手跑了兩次真實的效能測試,而且看得懂要觀察哪裡。
六、預習:之後怎麼請 Claude Code 幫你
今天的腳本是現成的,之後系列會改由 Claude Code 依你的需求產生腳本,也會有它的保姆級安裝教學。今天先預習「怎麼問」——因為問法的品質,直接決定你得到的腳本品質。以下三個 prompt 可以先收藏,等工具裝好就能直接用:
Prompt 1|請它解釋腳本(把看不懂變成看得懂)
我是不會寫程式的測試人員。請逐行解釋下面這個 k6 腳本在做什麼,
用白話文說明,不要假設我懂 JavaScript:
(貼上 first-test.js 的完整內容)
Prompt 2|請它解讀測試結果(把數字變成結論)
這是我剛跑完的 k6 輸出結果。請幫我解讀:
1. 這次測試整體是成功還是有問題?
2. 平均回應時間和 p(95) 各代表什麼意思?
3. 有沒有哪個數字需要特別注意?
(貼上終端機的完整輸出)
Prompt 3|請它修改腳本(並要求說明改了什麼)
請把這個 k6 腳本改成 20 個虛擬使用者、執行 60 秒,
並且告訴我你改了哪幾行、為什麼這樣改:
(貼上 first-test.js 的完整內容)
這三個 prompt 藏著同一個心法,也是整個系列反覆使用的模式:表明身分(不會寫程式的測試人員)+明確任務+要求解釋。表明身分讓回答不會充滿術語;要求解釋則確保你每次互動都有學到東西,而不是拿到一個黑盒子。
七、測試注意事項:按下執行之前,先讀這一段
效能測試工具本質上是「自動化的大量請求產生器」,用錯地方就是攻擊。以下注意事項 QA 與 RD 都必須知道,今天先建立底線:

給 RD 的一句話:上面每一條你可能都覺得是常識,但請幫忙守住第 3 條與第 6 條——在 code review 或環境設定上,讓測試環境與正式環境「長得明顯不一樣」,是工程端能給測試端最實際的保護。
八、觀念驗證:三個問題確認你有帶走今天的重點
不用寫答案,在心裡回答就好。答不出來就回到對應章節再看一次:
• 公司要辦週年慶,PM 問你「網站沒問題吧?」——功能測試全過的情況下,你還缺哪三個問題的答案?(第三節)
• 為什麼今天 20 個人的測試沒有比 1 個人明顯變慢?這代表測試失敗嗎?(第五節步驟 5)
• 同事說「我拿隔壁團隊的 API 來練習壓測」,你要阻止他——理由是注意事項的哪一條?(第七節)
九、小結
今天你做到了三件事:理解功能測試與效能測試回答的是不同的問題;認識容量、速度、穩定三個核心問題與負載曲線;最重要的是——親手安裝 k6、跑了兩次真實測試、做了第一次結果比較。你已經比多數「聽過效能測試」的人多走了一步:你跑過了。
附錄:本篇指令速查
# 安裝(Windows)
winget install k6 --source winget
# 安裝(macOS)
brew install k6
# 驗證安裝
k6 version
# 執行測試(使用腳本內設定:1 人 30 秒)
k6 run first-test.js
# 執行測試(覆寫為 20 人 30 秒)
k6 run --vus 20 --duration 30s first-test.js
iThome鐵人賽