以太坊 RPC 提供商根据每个方法的计算单元成本和并发窗口执行速率限制。诸如跨大范围的 eth_getLogs 和归档状态调用等重方法占主导。缓解措施包括批处理、缓存、缩小范围、使用 WebSocket 订阅、带 Retry-After 的指数退避,以及将持续负载移至专用端点。
直接回答:为什么你会遇到以太坊 RPC 的 429 错误
如果你从以太坊 RPC 端点收到 HTTP 429 Too Many Requests 错误,这意味着你的应用程序已超过提供商的速率限制。与超时(表示服务器未及时响应)或 JSON-RPC 错误(带有错误代码的有效响应)不同,429 是 HTTP 级别的响应,告诉你需要放慢速度。提供商通过为每个 JSON-RPC 方法分配计算单元成本来计量使用情况,并对每秒请求数和并发请求数实施限制。像 eth_getLogs 在大块范围或归档节点上的 eth_call 这样的重方法可能消耗数百个计算单元,迅速耗尽你的配额。
解决 429 的关键是理解成本模型并调整客户端行为。本文解释了机制,提供了可复现的 curl 演示,并概述了标准化的缓解策略。有关 429 处理的更广泛概述,请参阅我们的通用 RPC 429 处理指南。
以太坊 RPC 提供商如何计量使用:计算单元和窗口
包括 OnFinality 在内的以太坊 RPC 提供商通常使用计算单元(CU)系统来对 API 访问定价。每个方法根据其所需的计算资源具有权重。例如,简单的 eth_blockNumber 可能花费 1 CU,而跨大范围的 eth_getLogs 可能花费数百或数千 CU。提供商还执行两种类型的窗口:每秒请求限制(例如,每秒 100 个请求)和并发限制(例如,10 个同时请求)。当超过任一限制时,你会收到 429。
确切的 CU 值在提供商之间并不标准化;它们由每个提供商记录。例如,Alchemy 和 Infura 发布自己的 CU 表。OnFinality 的定价页面概述了我们的方法。下表显示了基于主要提供商记录行为的代表性范围;请将这些视为估计值,而非通用常量。
- eth_blockNumber: 1 CU(低)
- eth_getBalance: 2-10 CU(低到中)
- eth_call: 10-50 CU(中,取决于复杂度)
- eth_getLogs(单个区块):10-50 CU(中)
- eth_getLogs(大范围,例如 1000 个区块):500-2000+ CU(高)
- debug_traceTransaction: 100-500 CU(高,仅归档)
- eth_getStorageAt(归档):20-100 CU(中到高)
为什么 eth_getLogs 和归档方法占主导
eth_getLogs 因消耗高计算单元而臭名昭著,因为它扫描一系列区块并过滤日志。大范围(例如 10,000 个区块)可能导致节点处理大量数据,导致高 CPU 和 I/O 使用。类似地,归档方法如历史区块的 eth_getBalance 或 debug_traceTransaction 需要节点重放状态,这在计算上很昂贵。这些方法通常是生产应用中 429 的主要原因。
为了缓解,你应该缩小区块范围,使用索引过滤器,并缓存结果。例如,不要每分钟查询最近 10,000 个区块的日志,你可以只查询最新区块并将结果存储在本地数据库中。对于归档数据,考虑使用专用归档端点或提供经济高效归档访问的提供商,例如 OnFinality 的以太坊网络页面。
429 与超时与 JSON-RPC 错误代码
区分 429、超时和 JSON-RPC 错误很重要。429 是提供商网关返回的 HTTP 状态代码,表示你已超过速率限制。超时发生在服务器在指定时间内(例如 30 秒)未响应时,通常是由于重请求。JSON-RPC 错误是带有错误对象的有效 HTTP 200 响应,例如“execution reverted”或“method not found”。这些是不同的故障模式,需要不同的处理。
例如,429 应触发退避和重试,而超时可能需要降低请求复杂度。JSON-RPC 错误可能表明你的合约调用中存在错误。理解这些差异有助于你实现健壮的错误处理。
可复现演示:使用 curl 的 200 与 429
以下 curl 命令演示了成功请求和速率受限请求。将 YOUR_API_KEY 替换为你的 OnFinality API 密钥。第一个命令发送简单的 eth_blockNumber 请求,应返回带有 JSON 结果的 200。第二个命令在循环中发送一系列请求以触发 429;调整循环次数以超过你计划的限制。
注意:确切的速率限制取决于你的计划。OnFinality 的免费层允许每秒一定数量的请求;查看你的定价了解详情。要看到 429,你可能需要多次运行循环或使用像 eth_getLogs 这样的重方法。
curl -X POST https://ethereum-rpc.publicnode.com \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
# 预期:HTTP/1.1 200 OK,带有 JSON 结果,如 {"jsonrpc":"2.0","result":"0x...","id":1}
# 要触发 429,运行循环(调整次数以超过你的限制):
for i in $(seq 1 100); do
curl -s -o /dev/null -w "%{http_code}\n" \
-X POST https://ethereum-rpc.publicnode.com \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
done
# 预期:如果超过速率限制,一些响应将是 429。预期结果和如何验证
当你运行第一个 curl 时,你应该看到 200 状态和带有当前区块号的 JSON 响应。当你运行循环时,你可能会看到 200 和 429 响应的混合。429 响应体通常包含类似“Too Many Requests”的消息,并可能包含 Retry-After 头。要验证你的速率限制,请查看提供商的仪表板或文档。对于 OnFinality,你可以在 API 服务控制台中监控使用情况。
如果你没有看到 429,增加循环次数或使用更重的方法,如大范围的 eth_getLogs。请记住,速率限制是按 API 密钥的,因此使用公共端点可能有不同的限制。
标准化缓解策略
为避免 429,请实施以下策略:
批处理:将多个请求合并到单个 JSON-RPC 批处理中。这减少了 HTTP 请求的数量,如果提供商提供批量折扣,还可以降低 CU 消耗。有关详细信息,请参阅我们的批处理最佳实践姊妹篇。
缓存:在本地缓存余额、日志和其他数据。例如,将 eth_getBalance 结果缓存短 TTL(例如 15 秒)以避免重复调用。
缩小区块范围:对于 eth_getLogs,查询较小的范围(例如 100 个区块),并在需要时分页。
使用 WebSocket 订阅:不要轮询 eth_getBalance 或 eth_blockNumber,而是使用 eth_subscribe 接收推送更新。这减少了请求数量。
带 Retry-After 的指数退避:当你收到 429 时,等待 Retry-After 头(如果存在)或使用指数退避(例如 1 秒、2 秒、4 秒)再重试。
将持续负载移至专用端点:如果你有高流量的生产流量,请考虑使用具有更高限制的专用端点。OnFinality 为此提供专用端点。
// 示例:Node.js 中使用 Retry-After 的指数退避
const axios = require('axios');
async function rpcCall(method, params) {
const url = 'https://ethereum-rpc.publicnode.com';
const data = { jsonrpc: '2.0', method, params, id: 1 };
let retries = 0;
while (true) {
try {
const response = await axios.post(url, data);
return response.data;
} catch (error) {
if (error.response && error.response.status === 429) {
const retryAfter = parseInt(error.response.headers['retry-after'] || '0');
const delay = retryAfter > 0 ? retryAfter * 1000 : Math.min(1000 * 2 ** retries, 10000);
await new Promise(resolve => setTimeout(resolve, delay));
retries++;
} else {
throw error;
}
}
}
}
// 用法:rpcCall('eth_blockNumber', [])常见失败和修复
一个常见的失败是在代码中不处理 429,导致崩溃或数据丢失。另一个是开发和生产使用同一个 API 密钥,导致生产达到限制。第三个是轮询过于频繁;例如,当区块时间为 12 秒时,每秒轮询 eth_blockNumber。
修复包括:实现带退避的重试逻辑,为不同环境使用单独的 API 密钥,以及降低轮询频率。此外,考虑使用 WebSocket 订阅获取实时数据。有关更高级的故障排查,请参阅我们的 RPC 助手工具。
权衡和限制
虽然批处理减少了 HTTP 开销,但它可能增加错误处理的复杂性,因为批处理可能返回部分错误。缓存引入了陈旧性,这可能对某些应用程序不可接受。缩小区块范围可能会错过日志,如果你没有正确处理分页。WebSocket 订阅需要维护持久连接,这可能不适合无服务器环境。
此外,计算单元成本并不标准化;它们因提供商而异,并且可能变化。始终参考提供商的文档以获取最新值。对于 OnFinality,请参阅我们的定价页面。
后续步骤和进一步阅读
既然你了解了以太坊 RPC 速率限制,你可以实施缓解策略以减少 429 错误。首先审计你当前的 RPC 使用情况,以识别重方法。然后,应用批处理、缓存和退避。对于持续负载,请考虑专用端点。
探索更多资源:以太坊网络页面了解端点详情,RPC 助手比较提供商,API 服务用于监控,以及我们的学习中心获取更多教程。另请阅读通用 RPC 429 处理指南以获取更广泛的视角。