跳至內容
0%

我們如何重建歷史日誌以提升速度

作者:Alchemy

最後更新:2026年7月27日1 分鐘閱讀
我們如何重建 historical logs 以提升速度

問問任何一個在做 indexer、DEX aggregator 或鏈上監控系統的團隊,他們的應用程式在哪裡會變慢,答案幾乎都一樣:大範圍的 eth_getLogs。

這是一種掃描數千甚至數十萬個區塊來回答單一問題的呼叫。上個月有哪些 transfer 打到這個合約?這個範圍內有哪些 pool 改變了狀態?這個地址自上線以來觸發了哪些事件?這些讀取是真實應用程式的骨幹,也是最容易卡住的讀取。所以我們重建了服務它們的引擎,讓這個方法在每個地區的 p99 都快了超過兩倍。以下說明我們是怎麼做的。

eth_getLogs 是什麼,為什麼重要?

eth_getLogs 是一個 JSON-RPC 方法,回傳智慧合約在執行過程中發出的事件:token transfer、swap、approval,或是合約自訂的任何事件。你可以依合約地址、事件簽章或索引過的 topic 值(例如 Transfer 或 Approval)過濾,並用 fromBlock 和 toBlock 指定區塊範圍。簡單說:告訴它要找什麼、要往回找多遠,它就會回傳所有符合的事件。

這是 Ethereum 上事件驅動索引的基礎。沒有它,你就得逐一掃描每一筆交易來找出你關心的那些。有了它,你就能建立活動與 transfer feed、approval 監控,以及任何即時或歷史事件索引器。這是我們所服務的方法中,使用最頻繁、營運上最關鍵的方法之一。如果你對 log 和 topic 還不熟悉,我們的深入探討 eth_getLogs 用實例完整說明了請求與回應的結構。

這個方法的其餘部分則塑造了整個工程難題。許多服務商會限制單次查詢能涵蓋的區塊數量。Indexer 必須靠等待確認來處理鏈重組(reorg)。Topic 過濾只能比對已索引的欄位,非索引的參數則要從原始資料中解碼。而靠近鏈頭的呼叫對延遲很敏感,路由到錯誤的節點類型可能導致錯誤或空回應。

其中最影響延遲的部分是範圍大小。查詢單一區塊幾乎是瞬間完成。但對於重播歷史的 indexer,或是持續監控合約數週的監控系統來說,範圍很快就會變大,查詢成本也隨之攀升。這正是延遲從可忽略的誤差,變成限制客戶開發速度的瓶頸的地方。

大家都提供這個方法。但很少有人談論它背後的引擎,因為重建這個引擎成本高昂,多數服務商並沒有這麼做。

為什麼 p99 延遲比平均延遲更重要?

真正造成傷害的數字不是平均值,而是 p99:把所有請求從最快排到最慢,p99 就是那百分之一中最慢的一個。平均值會把它藏起來。你可能有 99 個請求在 60 毫秒內完成,但第一百個卻花了整整一秒。

那個最慢的請求,就是讓 dashboard 卡住、或讓 indexer 落後於鏈的那一個,也正是你的使用者盯著看的那一個。平均延遲看起來可能沒問題,但尾端延遲卻悄悄地拖垮整個工作負載。對於運行 indexer 和監控系統的團隊來說,尾端延遲就是工作負載本身。

我們如何優化 eth_getLogs?

我們重建了服務這個方法的儲存與查詢引擎,而不是去調校原本既有的系統。

要讓這樣的呼叫變快,有幾種做法:調整查詢參數、加上快取、限制可接受的範圍,或是砸更多同類型的硬體。大多數做法只能換來一點餘裕,並沒有從根本改變什麼。

我們做得更深入。我們沒有依賴把歷史 log 讀取視為一般工作負載的通用型受管理資料庫,而是運行了一套專門針對 getLogs 存取模式調校的儲存與查詢層:在非常龐大的資料集上進行快速的過濾掃描,並且跑在我們自行營運的專屬基礎設施上。

我們沒有調一個旋鈕,也沒有在舊系統上外掛一個快取。我們是在方法層級上投入資源,針對客戶最關鍵的呼叫之一背後的引擎進行投資。這是昂貴的、以方法為單位的基礎設施工程,也是為什麼改善會體現在尾端,而不只是平均值上。

結果如何?

重點很簡單:在每個地區,p99 都快了超過兩倍。

如果你運行的是 indexer 或監控系統,p99 就是拖垮你工作負載的延遲。更好的平均值固然不錯,但更好的尾端延遲才能讓 dashboard 保持反應靈敏、讓 indexer 跟得上鏈的進度。

已經有以嚴肅規模運行這套系統的團隊看到了成效。其中一家最大的加密貨幣交易所,把他們的歷史 log 讀取效能拿我們的引擎跟他們自己運行的節點做了基準測試,並在他們自己的工作負載上量測到 p99 有大幅改善。這是在生產環境中、用客戶自己的量測工具得出的證據,而不只是我們自己 dashboard 上的數字。

這對你來說意味著什麼?

如果你的應用程式依賴歷史 log 讀取來做索引、彙整或監控,你會得到更快的讀取速度,以及在每個地區都有大幅改善的 p99 尾端延遲,而且是跑在我們專為這個方法重建的基礎設施上。以下幾點值得你在實際使用時留意:

  1. 在 pay-as-you-go 和 enterprise 方案中,eth_getLogs 在 Ethereum、Base、Optimism、Arbitrum、Polygon、Robinhood 及其他主要鏈上都支援單次查詢不限區塊範圍,所以重播歷史不需要自己手動做分頁。
  2. 對於鏈頭附近的 log,WebSocket subscriptions 會在新 log 一產生時就推送給你,這樣你就能把 eth_getLogs 保留給它本來設計要處理的歷史讀取。
  3. 你的整合方式完全不需要改變。方法一樣、請求格式一樣,只是背後換了更快的引擎在服務。

在方法層級投入資源的意義在於:定義你工作負載的那些讀取,正是我們調校這套引擎所針對的對象。建立免費的 Alchemy 帳號,把你的 indexer 指向我們,親自用你自己的量測工具看看差異。

常見問題

eth_getLogs 會回傳什麼?

一個符合你過濾條件的事件 log 陣列:合約地址、事件簽章與索引過的 topic 值,以及區塊範圍。每一筆 log 都包含發出事件的地址、topics、資料內容,以及它所屬的區塊與交易。完整的請求與回應規格請參考 API reference。

為什麼對 indexer 來說,p99 延遲比平均延遲更重要?

因為 indexer 是依序或分批處理請求,最慢的請求會決定整體步調。平均值很低但尾端很長,代表 indexer 經常卡在那最慢的百分之一上,落後於鏈頭,並回傳過時的資料。p99 測量的正是這些請求。

在 Alchemy 上,單次 eth_getLogs 呼叫可以查詢多大的區塊範圍?

在免費方案中,每次查詢限制為 10 個區塊。在 pay-as-you-go 和 enterprise 方案中,Ethereum、Base、Optimism、Arbitrum、Polygon、Worldchain、BNB 以及其他數條鏈的區塊範圍不設上限,回應大小上限為 150MB。完整的各鏈對照表請見 eth_getLogs reference。

我該如何讓大範圍的歷史查詢維持快速?

盡可能縮小過濾範圍:指定合約地址與所需的事件 topic,而不只是區塊範圍。對於不支援不限範圍的鏈,遇到非常大的範圍時,把查詢拆成較小的區塊分批處理。至於未來的新 log,請改用 WebSocket subscriptions,而不是用輪詢的方式。

Alchemy 電子報

搶先掌握最新發布消息

訂閱我們的電子報

取得 Alchemy 最新產品更新與資源

A
O
D
+
超過 80,000 名訂閱者

輸入您的電子郵件地址,即表示您同意接收我們的行銷通訊與產品更新。您了解 Alchemy 會依照我們的隱私權聲明處理所收到的資訊。您可以隨時取消訂閱。