效能基準與調優
Tip
什麼時候需要讀這篇:關心事件吞吐與延遲數字、部署前容量評估、版本升級前後想對比效能回歸時。不需要則跳過,不影響其它功能的使用。
實測基準(2026-10-05,Python 3.13.14)
同一台機器前後兩輪實測(預熱 + 多輪取樣取百分位),NoneBot2 2.5.0 為獨立環境對照。
全部數字可用倉庫自帶基準重現:python tests/performance/benchmark.py。
事件分發(ops/s,越高越好)
| 基準項 | ErisPulse | NoneBot2 2.5.0 | 對比 |
|---|---|---|---|
| 匯流排單處理器序列延遲 | 9,189 | 3,021 | 3.0× |
| 匯流排洪泛吞吐(1000 事件/輪) | 9,877 | 2,055 | 4.8× |
| 10 處理器/事件吞吐 | 4,309 | 435 | 9.9× |
| 指令命中(/指令) | 2,165 | 677 | 3.2× |
| 指令 miss(非指令訊息) | 10,818 | 921 | 11.7× |
| 訊息橋單處理器(預設全鏈路) | 2,804 | 2,144 | 1.3× |
其它子系統能力(優化後)
| 基準項 | ops/s | 基準項 | 數值 |
|---|---|---|---|
| getConfig 熱讀 | 1,086,957 | ORM 單筆 create | 407/s |
| KV aset(sqlite) | 1,659 | GET /health(ASGI) | 1,188/s |
| KV aget(sqlite) | 3,333 | module.call RPC | 148,905/s |
| 端對端訊息往返 | 298 | 混合負載 | 142/s |
啟動耗時
| 階段 | ErisPulse | NoneBot2 |
|---|---|---|
| 直譯器空轉對照 | 59.5ms | — |
| 冷匯入 | 241.7ms | 249.6ms |
| sdk.init / NoneBot init | 30.8ms | 162.3ms |
自跑基準與回歸對比
# 快速檔(樣本數約 1/4,冒煙用)
python tests/performance/benchmark.py --quick
# 完整基線落盤(8 套件:config/event/storage/send/router/module/overall/startup)
python tests/performance/benchmark.py --json baseline.json
# 與舊基線對比(差值 ±5% 閾值內視為噪聲)
python tests/performance/benchmark.py --compare baseline.json
# HTML 報告 / 指定儲存套件後端
python tests/performance/benchmark.py --html report.html
python tests/performance/benchmark.py --backend mysql
CI 注意:基準數字隨機器浮動,
--compare的 ±5% 閾值只適合同一台機器的前後對比(升級驗證),不適合跨機器門禁。
調優要點
- 訊息橋全鏈路瓶頸在會話記錄:預設開啟 transcript 記錄(2.9 起記憶體緩衝 + 背景批次寫入磁碟);無稽核需求時可關閉,全鏈路吞吐約 2,804 → 3,774 ops/s
- GC 治理:
ErisPulse.framework的 proactive_gc 配置組(interval / full_every / memory_growth_mb /idle_only)——事件洪峰期自動跳過 GC;init 階段gc.freeze()已內建 - 儲存後端:本地單機 sqlite(WAL)足夠;多實例共享資料層切換 mysql / postgres(見儲存後端)
- 熱路徑已內建優化(2.9 起,無需配置):transcript 批次寫入磁碟、i18n 快取、日誌等級守衛、匹配器預編譯、配置延遲寫入統一沖刷至磁碟
- 指令治理狀態上限:冷卻/限流/配額狀態表上限 4096 筆(超限淘汰最舊),超大群規模部署無需調整
記憶體診斷
排查「越跑越吃記憶體」時,在可疑路徑前後各打一個帶 label 的快照,同名 label 自動計算增量(RSS + tracemalloc 雙指標):
from ErisPulse.runtime import log_snapshot, snapshot
class MyModule(BaseModule):
async def on_load(self, event):
snapshot("MyModule.load") # 採集並回傳 dict(含按 label 的 RSS delta)
async def on_unload(self, event):
log_snapshot("MyModule.unload") # 同口徑採集並記錄 TRACE 級日誌
snapshot(label)回傳機器可讀 dict,適合斷言與上報;log_snapshot(label)直接寫日誌(TRACE 級),適合臨時排查- label 快取有界,不會隨呼叫次數增長洩漏;配合
/metrics端點的行程指標 可做長期趨勢觀察 - 模組卸載後的殘留增長通常指向歸屬缺失(見歸屬權系統的
bind_owner背景任務條目)
相關文件
- 執行指標觀測:
/health(實例身分 / 事件計數)與/metrics(Prometheus 文字,ErisPulse.server.metrics_enabled開啟)見部署指南