RPC 提供商对比
RPC 提供商对比
本页内容正在整理中,欢迎贡献。
概述
RPC(Remote Procedure Call)节点是 DApp 与以太坊网络通信的入口。选择合适的 RPC 提供商对应用的稳定性、性能和成本至关重要。本文对比主流托管 RPC 服务商,并介绍去中心化 RPC 替代方案。
主要内容
主流托管 RPC 提供商
| 提供商 | 免费额度 | 特色功能 | 支持网络 |
|---|---|---|---|
| Alchemy | 300M CU/月 | NFT API、Webhooks、Debug API、AA SDK | 以太坊、L2、Polygon 等 |
| Infura | 100k 请求/天 | 老牌稳定、IPFS 网关 | 以太坊、L2、IPFS |
| QuickNode | 50M 积分/月 | 插件市场、Streams(Firehose) | 30+ 链 |
| Ankr | 1M 请求/月 | 多链统一 RPC | 30+ 链 |
| Blast API | 40M CU/月 | 去中心化节点聚合 | 以太坊、L2 等 |
免费方案汇总
不需要 API Key 的公共 RPC(适合测试,不建议生产使用):
// 公共 RPC 端点(可能限速/不稳定)const PUBLIC_RPCS = { mainnet: "https://ethereum.publicnode.com", sepolia: "https://ethereum-sepolia.publicnode.com", optimism: "https://mainnet.optimism.io", arbitrum: "https://arb1.arbitrum.io/rpc", base: "https://mainnet.base.org",};推荐使用 Chainlist 查找各网络的 RPC 列表。
配置示例
// Alchemyconst alchemyRpc = `https://eth-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`;
// Infuraconst infuraRpc = `https://mainnet.infura.io/v3/${process.env.INFURA_PROJECT_ID}`;
// QuickNodeconst quicknodeRpc = `https://xxx.quiknode.pro/${process.env.QUICKNODE_API_KEY}`;
// 多 provider 故障转移(使用 viem)import { createPublicClient, fallback, http } from "viem";import { mainnet } from "viem/chains";
const client = createPublicClient({ chain: mainnet, transport: fallback([ http(alchemyRpc), http(infuraRpc), http(quicknodeRpc), ]),});增强 API 功能对比
| 功能 | Alchemy | Infura | QuickNode |
|---|---|---|---|
eth_getLogs 无限范围 | ✅ | ❌(限 10k 块) | ✅ |
| NFT API | ✅ | ❌ | ✅ |
| Token API | ✅ | ❌ | ✅ |
| Webhook(实时事件) | ✅ | ✅ | ✅ |
Trace API(debug_*) | ✅ | ✅(付费) | ✅ |
| 模拟交易 | ✅ | ❌ | ✅ |
| 账户抽象 API | ✅ | ❌ | ✅ |
去中心化 RPC
避免中心化单点依赖:
| 方案 | 说明 |
|---|---|
| dRPC | 去中心化 RPC 网关,聚合多个节点提供商 |
| Lava Network | 去中心化 RPC 市场 |
| Pocket Network | 去中心化节点网络(POKT) |
| 自建节点 | 完全自主,详见自建节点 |
速率限制处理
// 实现指数退避重试async function callWithRetry<T>( fn: () => Promise<T>, maxRetries = 3): Promise<T> { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error: any) { if (error?.status === 429 && i < maxRetries - 1) { // 指数退避:等待 1s、2s、4s await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i))); continue; } throw error; } } throw new Error("Max retries exceeded");}成本优化建议
- 缓存读取结果:链上数据一旦最终化不会变化,可以缓存
- 批量请求:使用
eth_callmulticall 批量读取合约状态 - 只订阅必要事件:避免订阅高频触发的事件
- 区分网络:测试使用免费 RPC,生产才用付费方案