跨客戶端執行指標規範
原始提案文檔及規範由@rjl493456442提供:標準化以太坊性能指標 - HackMD
這項功能最初由Gary 發起,他在 Geth 中實現了慢速區塊日誌記錄。從那時起,我認為這項功能在很多方面都非常有用,如下所述,於是我與他合作,將其標準化並推進這一願景的實現。
我認為這有助於重新定價、ScaleL1跟蹤以及bloatnet(我目前關注的重點)。不過,我覺得我們能做的遠不止這些。
1. 引言與動機
這項計劃存在的意義
以太坊的多客戶端理念是一項核心優勢——但也帶來了一個挑戰:我們如何比較不同實現方式的性能?
標準化的執行指標通過以下方式解決了這個問題:
- 跨客戶端性能比較——公平、同等條件下的基準測試
- 網絡健康監控——在執行瓶頸影響共識之前識別它們。
- 數據驅動的協議研究——利用真實執行數據驗證EIP提案
- 異常檢測——檢測異常區塊(高 gas 消耗、複雜的狀態訪問模式)
實際案例:EIP-7907 分析
EIP-7907 分析恰恰說明了為什麼標準化的執行指標至關重要。
我使用 Geth 指標測量了以下內容:
- 代碼讀取延遲:107毫秒至904毫秒,具體取決於字節碼大小。
- 每次調用開銷擴展:5.9µs 至 49.9µs(從最小合約到最大合約增加 8.5 倍)
- 執行塊細分:隔離代碼讀取、賬戶讀取、EVM 執行和數據庫寫入
所有這些見解都有助於做出更明智的決策,從而大大簡化了ACD的決策流程。
2. 核心指標
指標按類別進行組織,涵蓋The Block執行生命週期:
| 類別 | JSON 路徑 | 描述 |
|---|---|---|
| 區塊信息 | block.* | 區塊編號、哈希值、gas 消耗量、交易次數 |
| 定時 | timing.* | 執行、驗證、提交和總耗時(毫秒) |
| 吞吐量 | throughput.* | 兆氣體/秒處理速率 |
| 州閱讀 | state_reads.* | 賬戶、存儲和代碼讀取操作 |
| 州政府撰寫 | state_writes.* | 賬戶和存儲變更 |
| 緩存 | cache.* | 賬戶、存儲和代碼緩存的命中率/未命中率 |
指標定義
| 指標 | 類型 | 描述 |
|---|---|---|
block.number | int64 | 方塊高度 |
block.hash | 細繩 | 區塊哈希(以 0x 為前綴) |
block.gas_used | int64 | 總燃氣消耗量 |
block.tx_count | int32 | 交易次數 |
timing.execution_ms | int64 | 執行交易所花費的時間 |
timing.state_read_ms | int64 | 讀取狀態(賬戶、存儲槽位和合約代碼)所花費的時間 |
timing.state_hash_ms | int64 | 花費在狀態重排上的時間 |
timing.total_ms | int64 | 總塊處理時間 |
throughput.mgas_per_sec | float64 | Gas吞吐量(gas_used / execution_time / 1e6) |
state_reads.accounts | int64 | 賬戶數據加載(餘額、隨機數、代碼哈希) |
state_reads.storage_slots | int64 | 存儲槽讀取 |
state_reads.code | int64 | 合約字節碼讀取 |
state_reads.code_bytes | int64 | 讀取的代碼總字節數 |
state_writes.accounts | int64 | 賬戶狀態更新 |
state_writes.storage_slots | int64 | 存儲槽寫入 |
state_writes.code | int64 | 合約字節碼寫入 |
state_writes.code_bytes | int64 | 代碼寫入總字節數 |
cache.{type}.hits | int64 | 賬戶/存儲/代碼的緩存命中次數 |
cache.{type}.misses | int64 | 緩存未命中(需要讀取數據庫) |
cache.{type}.hit_rate | float64 | 命中率:( (hits / (hits + misses)) * 100.0 |
3. 慢速塊 JSON 格式
當代碼塊執行時間超過可配置Threshold(默認值:1000毫秒)時,客戶端會輸出結構化的JSON日誌:
{ "level" : "warn" "msg" : "Slow block" "block" : { "number" : 19234567 "hash" : "0x1234...abcd" "gas_used" : 29500000 "tx_count" : 234 } "timing" : { "execution_ms" : 1250 "state_read_ms" : 320 "state_hash_ms" : 150 "commit_ms" : 75 "total_ms" : 1475 } "throughput" : { "mgas_per_sec" : 23.60 } "state_reads" : { "accounts" : 5420 "storage_slots" : 12340 "code" : 890 "code_bytes" : 456000 } "state_writes" : { "accounts" : 234 "storage_slots" : 1890 } "cache" : { "account" : { "hits" : 4800 , "misses" : 620 , "hit_rate" : 88.60 } "storage" : { "hits" : 10200 , "misses" : 2140 , "hit_rate" : 82.68 } "code" : { "hits" : 870 , "misses" : 20 , "hit_rate" : 97.75 } } }現場要求
| 場地 | 必需的 | 筆記 |
|---|---|---|
level , msg | ![]() | 必須是"warn"和"Slow block" |
block.* | ![]() | 所有模塊信息字段均為必填項 |
timing.execution_ms | ![]() | 核心時序指標 |
timing.state_read_ms | ![]() | 從數據庫/緩存讀取狀態所花費的時間 |
timing.state_hash_ms | ![]() | 花費在 Merkle trie 重述上的時間 |
timing.commit_ms | ![]() | 花費在將狀態持久化到存儲上的時間 |
timing.total_ms | ![]() | 端到端塊處理時間 |
throughput.mgas_per_sec | ![]() | 保留兩位Decimal |
state_reads.* | ![]() | 所有讀取計數器 |
state_writes.* | ![]() | 所有寫入計數器 |
cache.* | ![]() | 嵌套結構,包含命中/未命中/命中率 |
4.實施情況
5. 進一步改進
中期目標:進行更細緻的績效分析
| 改進 | 描述 | 理由 |
|---|---|---|
| 單筆交易指標 | 每個交易的時間和狀態訪問權限 | 找出導致速度減慢的具體交易。 |
| EVM 操作碼計數 | 加載、存儲、調用、創建、EXTCODECOPY | 瞭解執行模式,檢測拒絕服務攻擊向量。 |
| 唯一訪問跟蹤 | 唯一賬戶、存儲空間、合約 | 衡量狀態訪問多樣性和工作集大小 |
| 預編譯分解 | 預編譯計時(ecrecover、sha256、modexp) | 識別昂貴的加密操作 |
| 默克爾化時間 | 賬戶樹與存儲樹的重新哈希 | 精確確定狀態根的計算成本 |
| 內存/分配統計信息 | 峰值內存使用量,每個內存塊的分配量 | 跟蹤內存壓力以進行資源規劃 |
| Trie 深度統計 | 平均/最大trie遍歷深度 | 瞭解狀態膨脹的影響 |
| 並行執行指標 | 線程利用率、爭用統計信息 | 對於並行 EVM 實現 |
| 目擊者人數 | Verkle/無狀態見證數據大小 | 為無國籍客戶做準備 |
| 寒冷與溫暖的通道 | 區分首次訪問和緩存訪問 | EIP-2929 氣體分析 |
這篇文章的目的不僅在於告知大家相關信息,更重要的是徵求大家的反饋。我們想知道,對於團隊、研究人員以及其他任何人來說,還有哪些信息值得我們去挖掘/瞭解。例如,客戶難以收集的內部數據等等。
此外,我們也想知道我們可以用它做些什麼,我們有一些想法,並列出了一些目標。但我們相信,人們會比我們想到更多好點子。
謝謝。




