許多工程團隊在測試邊緣運算閘道器 (EdgeNode) 時,往往只專注於 「快樂路徑 (Happy Path)」:
然而,根據莫非定律 (Murphy's Law),「會發生的壞事,一定會在最糟糕的時間點發生」。現場實際運行的 EdgeNode 每天都在承受極端考驗:
如果沒有經過嚴苛的 「混沌工程 (Chaos Engineering)」 驗證,這些隱藏的 Race Condition (競態條件) 與 Deadlock (死鎖) 將會直接在產線現場爆發。
傳統的硬體壓力測試方法往往存在嚴重盲點:
工程師坐在桌前手動拔插 USB 線 10 次,沒發現異常就宣告測試通過。這種作法無法觸發「恰好在 fwrite 呼叫當下拔線」這種毫秒級別的 Race Condition Window。
隨機手動搞破壞,即便系統崩潰了,也無法重現 (Reproduce) 故障當下的精確時間點與記憶體狀態。
單元測試模擬的 Mock 物件過於理想化,無法反映 Linux 核心層 (Kernel Module)、USB OTG 驅動、以及實體 File System 在受壓時的真實物理行為。
為了全面驗證 EdgeNode 的韌性 (Resilience),我們採用 「破壞者模式 (Chaos Engine)」。透過自動化腳本,直接在 OS 核心層與應用層之間注入以下四大故障:

tc)利用 Linux 核心的 netem (Network Emulation) 模組,動態注入 500ms 延遲與 30% 丟包率,模擬惡劣的行動網路。
透過向 /sys/class/udc/3f980000.usb/soft_connect 寫入 0 或 disconnect,在毫秒級別精確切斷 USB 隨身碟模擬,模擬無預警拔線。
在正常的 UART 資料串流中,隨機插入偽造的 Header 或損壞的 Checksum 封包,驗證 Parser 的 Sanitization 防護。
chaos_monkey.py)以下為我們為 EdgeNode 打造的自動化錯誤注入測試工具:
#!/usr/bin/env python3
# /opt/gateway/tools/chaos_monkey.py
# EdgeNode 混沌工程與 Fault Injection 壓力測試腳本
import os
import sys
import time
import random
import subprocess
import threading
class ChaosMonkey:
def __init__(self, target_ip="10.0.0.5", duration_sec=60):
self.target_ip = target_ip
self.duration_sec = duration_sec
self.is_running = False
self.stats = {"network_faults": 0, "usb_unplugs": 0, "noise_injections": 0}
def inject_network_latency(self):
"""1. 模擬網路惡劣環境 (High Latency & Packet Loss)"""
print("[Chaos] 💥 注入網路延遲與丟包 (tc netem)...")
cmd_add = "sudo tc qdisc add dev wlan0 root netem delay 300ms 100ms loss 20%"
cmd_del = "sudo tc qdisc del dev wlan0 root netem 2>/dev/null"
subprocess.run(cmd_add, shell=True)
self.stats["network_faults"] += 1
time.sleep(random.uniform(5, 10))
subprocess.run(cmd_del, shell=True)
print("[Chaos] 🟢 恢復正常網路環境。")
def inject_usb_hot_unplug(self):
"""2. 毫秒級微秒切斷 USB OTG 連結 (Software Re-plug Attack)"""
print("[Chaos] 💥 觸發 USB OTG 軟體突襲式熱插拔...")
udc_path = "/sys/class/udc/3f980000.usb/soft_connect"
# 強制斷開 UDC
cmd_disconnect = "echo 'disconnect' | sudo tee /sys/class/udc/*/soft_connect > /dev/null 2>&1 || true"
cmd_connect = "echo 'connect' | sudo tee /sys/class/udc/*/soft_connect > /dev/null 2>&1 || true"
subprocess.run(cmd_disconnect, shell=True)
self.stats["usb_unplugs"] += 1
time.sleep(random.uniform(0.5, 2.0))
subprocess.run(cmd_connect, shell=True)
print("[Chaos] 🟢 重新掛載 USB OTG。")
def inject_uart_garbage_data(self):
"""3. 向序列埠寫入隨機垃圾訊號 (Noise Injection)"""
print("[Chaos] 💥 注入 UART 嘈雜干擾訊號...")
garbage = os.urandom(64)
try:
# 寫入虛擬或實體串口
with open("/dev/ttyAMA0", "wb", buffering=0) as f:
f.write(garbage)
self.stats["noise_injections"] += 1
except Exception as e:
pass
def run_stress_test(self):
"""主混沌測試迴圈"""
print(f"==================================================")
print(f" 🐒 啟動 EdgeNode 混沌工程測試 (預計執行 {self.duration_sec} 秒)")
print(f"==================================================")
self.is_running = True
start_time = time.time()
while time.time() - start_time < self.duration_sec:
# 隨機挑選破壞手段
action = random.choice([
self.inject_network_latency,
self.inject_usb_hot_unplug,
self.inject_uart_garbage_data
])
action()
time.sleep(random.uniform(3, 8))
self.is_running = False
print(f"\n==================================================")
print(f" 📊 測試結束!破壞統計報告:")
print(f" - 網路故障注入次數: {self.stats['network_faults']}")
print(f" - USB 突襲熱拔插次數: {self.stats['usb_unplugs']}")
print(f" - UART 雜訊注入次數: {self.stats['noise_injections']}")
print(f"==================================================")
if __name__ == "__main__":
monkey = ChaosMonkey(duration_sec=30)
monkey.run_stress_test()
經過 chaos_monkey.py 連續 24 小時不間斷的破壞注入後,EdgeNode 必須滿足以下指標,方可批准正式發布出貨:
systemd 服務必須保持 active (running),若有崩潰必須在 5 秒內自我重啟並自動修復檔案系統。在 Day 29 中,我們學會了如何「像敵手一樣思考」:
tc 網路干擾、UDC 突襲斷線與 UART 雜訊。明天將迎來本系列文章的最終章 Day 30:「[完賽回顧] 從原型到穩定出貨:開源這個邊緣運算閘道器的未竟之路」!