我有一台 Raspberry Pi 5,root 檔案系統跑在一顆外接 USB SSD 上,平常掛著一個常駐的 web 服務。某天它突然「連不上」——SSH、網頁全都沒反應,只能手動拔電重開。這篇記錄我怎麼一步步把原因鎖定到外接 SSD 的 USB 橋接晶片,以及最後怎麼修。
現象
- 服務與 SSH 全部無回應,整台機器像從網路上消失。
- 沒有任何預警,重開機後一切又正常。
- 直覺會以為是「網路斷線」,但事實不是。
第一步:這是斷線,還是整台凍死?
關鍵證據在系統日誌。先看上一次開機(-1)的日誌尾端:
1 | journalctl -b -1 --no-pager | tail -60 |
結果日誌在 20:12:30 戛然而止,停在服務每隔幾秒一次的正常輪詢中間,之後直到我手動重開(約 47 分鐘後)完全空白。再對照開關機記錄:
1 | last -x reboot shutdown | head |
兩次開機之間沒有 shutdown 記錄——代表系統不是正常關機,是被硬斷電的。
這兩點合起來說明:不是網路掉線,也不是單一服務崩潰(那樣其他服務還會繼續寫日誌),而是 journald 本身都停止寫入 = 整個作業系統凍死(hard freeze),所以才會「連不上」。
第二步:逐一排除常見死因
Pi 當機最常見的幾個原因,用日誌與現場狀態逐一排除:
| 嫌疑 | 檢查方式 | 結果 |
|---|---|---|
| 欠壓 / 電源不穩 | vcgencmd get_throttled、journal 搜尋 under-voltage |
0x0,全程無記錄 ❌ |
| 過熱降頻 | vcgencmd measure_temp |
~60°C,無 thermal throttle ❌ |
| 記憶體耗盡(OOM) | journal 搜尋 oom-kill |
記憶體充足、swap 沒動 ❌ |
| Kernel panic / soft-lockup / RCU stall | journalctl -b -1 -k 搜尋 |
完全沒有 ❌ |
| 磁碟寫滿 | df -h / |
只用 29% ❌ |
| SSD 硬體故障 | smartctl -H /dev/sda |
PASSED(碟本身健康)❌ |
軟體、電源、溫度、記憶體、磁碟空間、硬碟健康——全部排除。一個「什麼都沒記錄到」的完全凍死,開始把矛頭指向底層硬體。
第三步:鎖定根因
先看 root 到底掛在什麼裝置上:
1 | lsblk -o NAME,SIZE,TYPE,TRAN,MODEL,MOUNTPOINT |
答案是:root(/dev/sda2)在一顆外接 USB SSD 上,透過 Realtek RTL9210B-CG(USB id 0bda:9210,一顆 M.2 NVMe → USB 橋接晶片)連接,且目前綁在 uas 驅動(USB Attached SCSI)上。
再看 USB 連結的健康狀況,兩次開機都各有幾筆:
1 | usb 2-1: Enable of device-initiated U1 failed. |
這是這顆橋接晶片 USB3 連結電源狀態(LPM)協商不良的訊號。
RTL9210 / RTL9210B + UAS + Pi 是社群裡惡名昭彰的組合:這顆橋接在 UAS 模式下、連結不穩時會突然從 USB 匯流排掉線。而因為 root 就在這顆碟上,一旦碟消失,kernel 連日誌都寫不進去(記錄目標沒了),整台機器瞬間凍住、網路全死,只能硬斷電——這正好完美對上我們看到的指紋。
誠實說一句:因為是「凍死」,當下那一刻按定義寫不出任何 log,所以不存在一行「鐵證日誌」。以上是「排除法 + 硬體指紋 + 前後的 U1/U2 失敗」三者共同指向的高信心結論。
修復:停用這顆橋接的 UAS
最簡單有效的做法,是針對這顆橋接停用 UAS,退回較保守但穩定的 BOT(Bulk-Only Transport)模式。在 /boot/firmware/cmdline.txt(必須維持單行)結尾加上:
1 | usb-storage.quirks=0bda:9210:u |
0bda:9210 是這顆橋接的 vid:pid,:u 代表對它停用 UAS。改完重開機生效。
修改前務必備份(root 在這顆碟上,動開機參數要小心):
1 | sudo cp -a /boot/firmware/cmdline.txt /boot/firmware/cmdline.txt.bak-$(date +%Y%m%d-%H%M%S) |
重開機後驗證是否生效:
1 | # 驅動應該從 uas 換成 usb-storage |
看到這兩行就對了:
1 | usb 2-1: UAS is ignored for this device, using usb-storage instead |
效能代價:實測 UAS vs BOT
停用 UAS 一定有代價,但到底掉多少?我用 fio 在改動前後各跑一次相同測試(測試檔寫在真正的 SSD 上、--direct=1 繞過 cache):
| 測項 | UAS(前) | BOT(後) | 變化 |
|---|---|---|---|
| 循序讀 (1M, QD16) | 389 MB/s | 373 MB/s | −4% |
| 循序寫 (1M, QD16) | 360 MB/s | 349 MB/s | −3% |
| 隨機讀 4K QD32 | 32.4k IOPS | 6.5k IOPS | −80% |
| 隨機寫 4K QD32 | 34.8k IOPS | 7.4k IOPS | −79% |
| 隨機讀 4K QD1 | 6,302 IOPS | 6,378 IOPS | ~持平 |
解讀:
- 循序讀寫幾乎無損(−3~4%):開機、複製大檔、備份完全無感。
- QD1(一次一條操作)完全沒變:單執行緒、延遲受限的存取不受影響。
- 深佇列隨機 IOPS 掉約 80%:這就是 UAS 指令佇列消失的代價。注意 BOT 的 QD32 成績幾乎等於它自己的 QD1——證明 BOT 把並發請求序列化成一次一條了。
換句話說,只有在「大量小 I/O 同時打」的場景(例如高並發資料庫)才會明顯感覺到。對低並發、以序列小讀寫為主的服務來說,日常幾乎無感。拿深佇列隨機 IOPS 換「不再整台凍死、不用拔電」,對一台要穩定常駐的機器絕對划算。
完整的測試腳本與原始數據我一併放在本文同目錄:
ssd_bench.sh、bench_uas_baseline.txt、bench_bot_after.txt。
更徹底的方案
如果很在意那 80% 的隨機 IOPS,或掉線仍偶發,最終解是把 M.2 NVMe 從 USB 轉接盒移到 Pi 5 官方的 NVMe HAT,走原生 PCIe,完全繞開 USB 橋接——穩定性與速度兩者都贏,隨機效能不但拿回來還更快。
加一層監控
修完不能只靠「感覺沒再當」。我寫了一個小腳本掛 cron 每 5 分鐘檢查一次:SSD 溫度(smartctl -A)、SoC 溫度與 throttle 旗標(vcgencmd)、SMART 健康、以及最近的 kernel USB/儲存錯誤(掉線的前兆),任何異常就在日誌標上 [WARN] / [ALERT]:
1 | */5 * * * * ~/ssd_monitor.sh >/dev/null 2>&1 |
正常時每行長這樣,之後要回頭查有沒有過熱或掉線,grep 一下 WARN/ALERT 即可:
1 | 2026-08-22 21:32:44 [OK] ssd=36C soc=59.8C throttled=0x0 health=PASSED drv=usb-storage |
小結
- 先分清楚是「斷線」還是「凍死」:看 journald 是否整個停止寫入、有沒有 shutdown 記錄,比什麼都關鍵。
- 用排除法縮小範圍:電源、溫度、OOM、panic、磁碟、SMART 一輪掃過。
- root 在外接 USB SSD 上時,橋接晶片掉線會拖垮整台機器——RTL9210 + UAS 是已知雷區,
usb-storage.quirks=<vid>:<pid>:u是便宜有效的解法。 - 代價心裡有數:循序幾乎無損,深佇列隨機 IOPS 是主要犧牲;真要效能就上 NVMe HAT。
- 修完補上監控,用數據確認問題真的走了。