目录结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
crpc/
├── migration/            # 数据库SQL迁移文件
│   ├── init_database.sql      # 数据库初始化(表结构+索引)
│   └── insert_rpc_nodes.sql   # RPC节点配置数据
├── config/               # 配置文件
│   ├── config.toml      # 主配置文件
│   └── nginx.conf       # Nginx负载均衡配置
├── program/              # Go源码
│   ├── main.go          # 程序入口
│   ├── go.mod           # Go模块定义
│   ├── go.sum           # 依赖锁定文件
│   ├── api/             # API接口层
│   ├── cleanup/         # 日志自动清理
│   ├── config/          # 配置管理
│   ├── database/        # 数据库操作
│   ├── health/          # 健康检查
│   ├── logger/          # 日志管理
│   ├── models/          # 数据模型
│   └── proxy/           # RPC代理和故障切换
├── scripts/              # 脚本文件
│   ├── init_db.sh               # 数据库初始化
│   ├── start_multi_instance.sh  # 启动多实例(开发)
│   ├── deploy_to_remote.sh      # 单实例远程部署
│   ├── deploy_multi_instance.sh # 多实例远程部署
│   ├── benchmark.sh             # 性能基准测试
│   ├── monitor.sh               # 实时监控面板
│   ├── test_api.sh              # API测试
│   ├── test_batch_requests.sh   # 批量请求测试
│   └── test_rpc_realworld.sh    # 真实交易测试
├── bin/                  # 编译后的二进制文件
│   └── crpc            # 可执行程序
├── log/                  # 日志文件目录
├── Makefile             # 构建脚本
└── README.org           # 项目文档(本文件)

项目简介

CRPC 是一个高可用的多链 RPC 代理服务,解决区块链应用中 RPC 节点不稳定的问题。

核心问题

前端直连RPC节点存在的问题:

  1. ❌ 节点故障导致业务中断
  2. ❌ 节点地址硬编码在前端
  3. ❌ 节点变更需要重新发布前端
  4. ❌ 无法统一管理和监控
  5. ❌ 无法实现负载均衡和故障切换

解决方案

通过后端RPC代理服务 + 多实例高可用架构,提供:

  • ⚡ *自动故障切换*:节点故障自动切换到备用节点
  • 🔄 *负载均衡*:支持多种负载均衡策略
  • 💪 *高可用部署*:支持多实例部署,单实例故障不影响服务
  • 🏥 *健康检查*:定期检测节点健康状态
  • 📊 *监控统计*:完整的请求和节点统计
  • 🔧 *易于管理*:RESTful API 管理节点配置

技术栈

  • *后端*:Go 1.21 + Gin
  • *数据库*:PostgreSQL 15
  • *负载均衡*:Nginx
  • *配置管理*:TOML

快速开始

环境要求

软件依赖

  • Go 1.21+
  • PostgreSQL 15+
  • Nginx(生产环境)

硬件建议

  • CPU: 2核+
  • 内存: 4GB+
  • 磁盘: 20GB+

本地开发部署

1. 准备数据库

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 确保PostgreSQL已安装并运行
sudo systemctl start postgresql

# 创建数据库和用户
sudo -u postgres psql << EOF
CREATE DATABASE crpc;
CREATE USER crpc WITH PASSWORD 'crpc_password';
GRANT ALL PRIVILEGES ON DATABASE crpc TO crpc;
\q
EOF

2. 初始化数据库

1
2
3
4
5
# 进入项目目录
cd /home/smokey/Desktop/crpc

# 运行数据库迁移
make migrate

3. 配置RPC节点

系统提供了预配置的RPC节点,包括:

  • ✅ 19条主流区块链(Ethereum、BSC、Arbitrum、Polygon、Solana等)
  • ✅ 50+ 公共RPC节点
  • ✅ 自动优先级分级
1
2
# 插入预配置的节点
make insert-nodes

*优先级策略*:

提供商类型 Priority Weight 说明
Chainstack(付费) 1 20 速度快、稳定性高
Infura(免费) 2 15 稳定但有限流
公共节点 3 10 免费但可能不稳定

*说明*:

  • priority 值越小优先级越高
  • weight 用于同优先级节点的权重随机选择
  • 系统会优先选择 priority 最小的健康节点
  • 如果高优先级节点全部故障,会自动降级使用低优先级节点

*节点选择逻辑*:

1
2
3
4
1. 筛选健康节点(is_healthy = true)
2. 按 priority 排序,选择最小值的节点组
3. 在同优先级组内,根据 weight 进行加权随机选择
4. 考虑平均响应时间(avg_response_time)进行微调

4. 配置文件

编辑 config/config.toml,确认数据库连接信息:

1
2
3
4
5
6
[database]
host = "localhost"
port = 5432
user = "crpc"
password = "crpc_password"
dbname = "crpc"

5. 安装依赖并运行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 安装Go依赖
make deps

# 编译程序
make build

# 运行(单实例)
make run

# 或者直接运行
cd program && go run main.go

5. 验证安装

1
2
3
4
5
# 检查服务健康状态
curl http://localhost:8080/health

# 预期输出:
# {"status":"ok","instance_id":"crpc-1"}

多实例部署

使用脚本启动多实例

启动方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
cd scripts

# 方式1:Unix Socket模式(推荐,性能最佳)
./start_multi_instance.sh 3 socket

# 方式2:HTTP模式(跨服务器部署)
./start_multi_instance.sh 3 http

# 方式3:双监听模式(同时支持Socket和HTTP)
./start_multi_instance.sh 3 both

# 查看日志
tail -f ../log/crpc-*.log

# 查看Socket文件(socket模式)
ls -lh /tmp/crpc-*.sock

性能对比

监听方式 延迟 吞吐量 使用场景
Unix Socket ~5-10μs 最高 同一服务器(推荐)✅
TCP (localhost) ~50-100μs 本地或跨服务器
TCP (网络) >1ms 跨服务器部署

**性能提升**:Unix Socket 比 TCP 快 **5-10倍**!

配置Nginx负载均衡

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 安装Nginx
sudo apt install nginx

# 复制配置文件
sudo cp config/nginx.conf /etc/nginx/nginx.conf

# 测试配置
sudo nginx -t

# 启动Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

验证负载均衡

1
2
3
4
5
6
7
# 多次请求,观察instance_id变化
for i in {1..10}; do
  curl -s http://localhost/health | jq .instance_id
  sleep 1
done

# 应该看到 crpc-1, crpc-2, crpc-3 轮流出现

使用示例

RPC请求

以太坊主网

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 获取最新区块号
curl -X POST http://localhost/ethereum \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# 响应示例:
# {
#   "jsonrpc": "2.0",
#   "result": "0x123456",
#   "id": 1
# }

BSC

1
2
3
4
5
6
7
8
9
# 获取账户余额
curl -X POST http://localhost/bsc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "method":"eth_getBalance",
    "params":["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", "latest"],
    "id":1
  }'

节点管理

获取所有链

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
curl http://localhost/api/chains | jq

# 响应示例:
# {
#   "code": 0,
#   "msg": "success",
#   "data": [
#     {
#       "chain_id": "ethereum",
#       "chain_name": "Ethereum Mainnet",
#       "description": "以太坊主网"
#     }
#   ]
# }

获取节点列表

1
2
3
4
5
# 获取以太坊的所有节点
curl http://localhost/api/nodes?chain_id=ethereum | jq

# 获取所有链的节点
curl http://localhost/api/nodes | jq

添加新节点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
curl -X POST http://localhost/api/nodes \
  -H "Content-Type: application/json" \
  -d '{
    "chain_id": "ethereum",
    "node_url": "https://your-custom-rpc.com",
    "provider": "Your Provider",
    "priority": 10,
    "weight": 5,
    "is_active": true
  }'

更新节点

1
2
3
4
5
6
7
8
9
# 禁用某个节点
curl -X PUT http://localhost/api/nodes/1 \
  -H "Content-Type: application/json" \
  -d '{"is_active": false}'

# 更新节点优先级
curl -X PUT http://localhost/api/nodes/1 \
  -H "Content-Type: application/json" \
  -d '{"priority": 5, "weight": 20}'

删除节点

1
curl -X DELETE http://localhost/api/nodes/1

获取节点统计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
curl http://localhost/api/stats/nodes | jq

# 响应示例:
# {
#   "code": 0,
#   "msg": "success",
#   "data": {
#     "ethereum": {
#       "total": 3,
#       "healthy": 2
#     },
#     "bsc": {
#       "total": 2,
#       "healthy": 2
#     }
#   }
# }

前端集成示例

JavaScript/TypeScript

1
2
3
4
5
6
7
8
9
// 旧代码(直接连接RPC节点)
const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com');

// 新代码(使用CRPC代理,按链ID挂在根路径)
const provider = new ethers.JsonRpcProvider('http://localhost/ethereum');

// 就这么简单!无需其他修改
const blockNumber = await provider.getBlockNumber();
console.log('当前区块:', blockNumber);

Python

1
2
3
4
5
6
7
8
from web3 import Web3

# 使用CRPC代理
w3 = Web3(Web3.HTTPProvider('http://localhost/ethereum'))

# 无需其他修改
block_number = w3.eth.block_number
print(f'当前区块: {block_number}')

React 示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { ethers } from 'ethers';

// 配置文件
const RPC_ENDPOINTS = {
  ethereum: 'http://localhost/ethereum',
  bsc: 'http://localhost/bsc',
  polygon: 'http://localhost/polygon',
};

// 创建Provider
function useProvider(chainId) {
  const [provider, setProvider] = useState(null);

  useEffect(() => {
    const endpoint = RPC_ENDPOINTS[chainId];
    if (endpoint) {
      setProvider(new ethers.JsonRpcProvider(endpoint));
    }
  }, [chainId]);

  return provider;
}

双监听模式(HTTP + Unix Socket)

CRPC支持**HTTP (TCP)** 和 Unix Socket 两种监听方式,可单独使用或同时启用。

为什么需要Unix Socket?

性能优势

当Nginx和CRPC在**同一台服务器**时,Unix Socket比TCP快得多:

对比项 TCP (localhost) Unix Socket 提升
延迟 ~50-100μs ~5-10μs 5-10倍 ⚡
吞吐量 极高 约30-40% ⬆️
CPU占用 减少20-30%
内核切换 需要TCP/IP栈 直接内核通信 无协议开销

原理

1
2
3
4
5
6
7
HTTP (TCP):
  应用 → Socket → TCP层 → IP层 → 网卡驱动 → 回环 → 网卡驱动 → IP层 → TCP层 → Socket → 应用
  ↑ 需要完整的网络协议栈处理

Unix Socket:
  应用 → VFS → Socket缓冲区 → VFS → 应用
  ↑ 直接内核通信,无需协议栈

使用场景

场景 推荐模式 原因
Nginx和CRPC同一台服务器 Unix Socket 性能最佳 ✅
CRPC跨多台服务器部署 HTTP (TCP) Socket无法跨网络
混合部署(本地+远程) 双监听模式 灵活性最高
开发调试 HTTP 便于直接访问

配置示例

场景1:纯Socket模式(推荐,生产环境)

配置文件 (config/config.toml):

1
2
3
4
5
6
7
8
[server]
port = 8080
instance_id = "crpc-1"
enable_http = false     # 关闭HTTP
enable_socket = true    # 启用Socket
# ⚠️ 注意:生产环境不要把socket放在/tmp下,避免Nginx的PrivateTmp=true导致不可见
# 开发环境示例:socket_path = "/tmp/crpc-1.sock"
socket_path = "/srv/crpc/crpc-1.sock"   # 生产环境推荐路径(与服务目录一致)

Nginx配置 (config/nginx.conf):

1
2
3
4
5
6
7
8
9
upstream crpc_backend {
    least_conn;
    # 生产环境推荐:与上面的socket_path保持一致
    server unix:/srv/crpc/crpc-1.sock max_fails=3 fail_timeout=30s;
    # 如需多实例,可配置 crpc-2.sock / crpc-3.sock
    # server unix:/srv/crpc/crpc-2.sock max_fails=3 fail_timeout=30s;
    # server unix:/srv/crpc/crpc-3.sock max_fails=3 fail_timeout=30s;
    keepalive 64;
}

*启动*:

1
./scripts/start_multi_instance.sh 3 socket

场景2:纯HTTP模式

*配置文件*:

1
2
3
4
5
[server]
port = 8080
instance_id = "crpc-1"
enable_http = true      # 启用HTTP
enable_socket = false   # 关闭Socket

*Nginx配置*:

1
2
3
4
5
6
7
upstream crpc_backend {
    least_conn;
    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8081 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8082 max_fails=3 fail_timeout=30s;
    keepalive 32;
}

*启动*:

1
./scripts/start_multi_instance.sh 3 http

场景3:双监听模式(最灵活)

*配置文件*:

1
2
3
4
5
6
[server]
port = 8080
instance_id = "crpc-1"
enable_http = true      # 同时启用HTTP
enable_socket = true    # 同时启用Socket
socket_path = "/tmp/crpc-1.sock"

*好处*:

  • ✅ Nginx通过Socket访问(性能最佳)
  • ✅ 可以直接HTTP调试: curl http://localhost:8080/health
  • ✅ 支持混合upstream(本地Socket + 远程HTTP)

*Nginx混合配置*:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
upstream crpc_backend {
    least_conn;

    # 本地实例(Unix Socket,优先级高)
    server unix:/tmp/crpc-1.sock max_fails=3 fail_timeout=30s weight=2;
    server unix:/tmp/crpc-2.sock max_fails=3 fail_timeout=30s weight=2;

    # 远程实例(HTTP,优先级低)
    server 192.168.1.100:8080 max_fails=3 fail_timeout=30s weight=1;

    keepalive 64;
}

*启动*:

1
./scripts/start_multi_instance.sh 3 both

验证和测试

验证Socket监听

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 查看socket文件
ls -lh /tmp/crpc-*.sock
# 输出:srw-rw-rw- 1 user group 0 Nov 17 10:00 /tmp/crpc-1.sock

# 测试socket连接(使用curl)
curl --unix-socket /tmp/crpc-1.sock http://localhost/health
# 输出:{"status":"ok","instance_id":"crpc-1"}

# 查看进程监听
ss -xl | grep crpc
# 输出:u_str LISTEN 0 128 /tmp/crpc-1.sock

性能测试

1
2
3
4
5
6
7
# 测试TCP性能
ab -n 10000 -c 100 http://localhost:8080/health

# 测试Socket性能(通过Nginx)
ab -n 10000 -c 100 http://localhost/health

# 对比QPS(Socket通常高20-30%)

故障排查

问题1:Socket文件不存在

*症状*:Nginx报错 connect() to unix:/tmp/crpc-1.sock failed (2: No such file or directory)

*解决*:

1
2
3
4
5
6
7
8
# 1. 检查CRPC是否启动
ps aux | grep crpc

# 2. 检查配置
grep enable_socket config/config.toml

# 3. 查看日志
tail -f log/crpc-1.log | grep -i socket

问题2:权限被拒绝

*症状*:Nginx报错 connect() to unix:/tmp/crpc-1.sock failed (13: Permission denied)

*解决*:

1
2
3
4
5
6
7
8
# 检查socket权限
ls -l /tmp/crpc-*.sock
# 应该是:srw-rw-rw-

# 如果不是,手动设置
chmod 666 /tmp/crpc-*.sock

# 或者修改代码中的chmod调用

问题3:旧socket文件占用

*症状*:启动失败,提示 address already in use

*解决*:

1
2
3
4
5
# 清理旧socket文件
rm -f /tmp/crpc-*.sock

# 重启服务
./scripts/start_multi_instance.sh 3 socket

最佳实践

  1. **生产环境推荐Socket**:Nginx和CRPC同服务器时,优先使用Unix Socket
  2. **Socket路径选择**:使用 /tmp//var/run/,确保权限正确
  3. **定期清理**:重启时先清理旧socket文件
  4. **监控文件数**:ulimit -n 确保足够的文件描述符
  5. **Keepalive调优**:Socket模式可以使用更大的keepalive值(64+)
  6. **备份方案**:同时启用HTTP,便于应急和调试

系统架构

整体架构图

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
┌─────────────────────────────────────────────┐
│              前端应用                        │
│  只需要知道一个固定的代理域名                │
│  https://crpc.coinexus.life/{chain}        │
└─────────────────┬───────────────────────────┘
┌─────────────────────────────────────────────┐
│         Nginx 负载均衡器                     │
│  - 使用 least_conn 策略                     │
│  - 自动检测后端健康状态                      │
│  - 失败自动重试其他实例                      │
└──────────┬──────────────┬───────────────────┘
           │              │
    ┌──────┴──────┬───────┴──────┬
    ↓             ↓              ↓
┌────────┐   ┌────────┐    ┌────────┐
│ CRPC-1 │   │ CRPC-2 │    │ CRPC-3 │
│ 实例1  │   │ 实例2  │    │ 实例3  │
│ 8080   │   │ 8081   │    │ 8082   │
└───┬────┘   └───┬────┘    └───┬────┘
    │            │              │
    └────────────┴──────────────┘
                 ↓ (共享同一个数据库)
         ┌──────────────┐
         │ PostgreSQL   │
         │ - 节点配置    │
         │ - 健康状态    │
         │ - 统计数据    │
         └──────┬───────┘
                ↓ (转发到健康节点)
    ┌───────────────────────────┐
    │     多个RPC节点池          │
    │  Ethereum: 3个节点         │
    │  BSC: 2个节点              │
    │  Polygon: 3个节点          │
    └───────────────────────────┘

多实例实现原理

1. 无状态服务设计

所有CRPC实例都是 完全无状态 的:

  • ✅ 不保存任何会话信息
  • ✅ 不缓存任何节点数据(从数据库实时读取)
  • ✅ 可以随时启动/停止任何实例
  • ✅ 可以动态增加/减少实例数量
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 每次请求都从数据库获取最新的节点列表
func (p *Proxy) ForwardRequest(ctx context.Context, chainID string, rpcReq *models.RPCRequest) (*models.RPCResponse, error) {
    // 从数据库实时获取健康节点
    nodes, err := p.db.GetHealthyNodes(chainID)
    if err != nil {
        return nil, err
    }

    // 选择节点并转发请求
    node := p.selectNode(nodes)
    return p.sendRequest(ctx, node, rpcReq)
}

2. 共享数据库存储

所有状态和配置都存储在 PostgreSQL 中:

  • *链配置*:chains 表
  • *RPC节点配置*:rpc_nodes 表(URL、优先级、权重等)
  • *节点健康状态*:is_healthy、failure_count、avg_response_time
  • *健康检查日志*:health_check_logs 表
  • *请求日志*:request_logs 表(可选)

3. Nginx 负载均衡

使用 least_conn 策略分发请求:

1
2
3
4
5
6
7
8
9
upstream crpc_backend {
    least_conn;  # 选择连接数最少的实例

    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8081 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8082 max_fails=3 fail_timeout=30s;

    keepalive 32;  # 保持长连接
}

*负载均衡策略*:

  • least_conn:选择当前连接数最少的实例(推荐)
  • round_robin:轮询(默认)
  • ip_hash:同一客户端IP总是转发到同一实例
  • weight:加权负载均衡

4. 分布式健康检查

每个实例独立运行健康检查,通过数据库更新节点状态。虽然多个实例都会检查,但这是有意为之:

  • ✅ 提高可靠性(一个实例宕机不影响检查)
  • ✅ 数据库写入量不大(每个节点10秒一次)
  • ✅ 可以看到不同实例视角的健康状态
  • ✅ 检查日志记录了 checked_by 字段区分来源

5. 自动故障切换

*实例级别故障切换*:

  • 任意实例宕机,Nginx自动将流量转移到其他实例
  • 连续3次失败标记为不可用30秒
  • 自动恢复可用实例

*节点级别故障切换*:

  • 只选择健康节点进行转发
  • 请求失败自动重试其他节点
  • 连续失败3次标记节点为不健康

工作流程

  1. 前端发送RPC请求到Nginx
  2. Nginx根据负载策略选择一个CRPC实例
  3. CRPC实例从数据库查询该链的健康节点
  4. 根据优先级和权重选择节点发送请求
  5. 请求失败自动重试其他节点
  6. 返回结果给前端
  7. 后台健康检查定期更新节点状态

为什么选择这个架构?

特性 我们的选择 原因
数据存储 PostgreSQL 强一致性、完整ACID、SQL查询强大
负载均衡 Nginx 性能优秀、配置简单、生态成熟
服务设计 无状态 易扩展、易维护、可随时重启
健康检查 分布式(不加锁) 提高可靠性、避免单点故障

RPC节点配置

支持的区块链

系统预配置了以下主流区块链网络:

EVM链

  • 以太坊系列

    • ethereum - Ethereum Mainnet
    • sepolia - Ethereum Sepolia 测试网
    • goerli - Ethereum Goerli 测试网
  • Layer 2

    • arbitrum - Arbitrum One L2主网
    • arbitrum-sepolia - Arbitrum Sepolia 测试网
    • optimism - Optimism L2主网
    • base - Coinbase Base L2
    • zksync - zkSync Era主网
  • BSC

    • bsc - BNB Smart Chain 主网
    • bsc-testnet - BSC 测试网
  • Polygon

    • polygon - Polygon 主网
    • polygon-mumbai - Polygon Mumbai 测试网
    • polygon-zkevm - Polygon zkEVM
  • 其他EVM链

    • avalanche - Avalanche C-Chain
    • fantom - Fantom Opera
    • cronos - Cronos 主网

非EVM链

  • Solana

    • solana - Solana 主网
    • solana-testnet - Solana 测试网
    • solana-devnet - Solana 开发网
  • Tron

    • tron - Tron 主网

特殊端点说明

某些区块链网络提供多种类型的API端点,需要根据具体用途选择:

Ethereum 多端点支持

端点类型 用途 示例
执行层 RPC 标准 eth_* 调用、交易、合约 /234582f3d3f0555c0c6817de16a0d346
WebSocket 实时订阅(新区块、交易等) wss://.../234582f3d3f0555c0c6817de16a0d346
Beacon API PoS共识层、验证者、质押 /beacon/234582f3d3f0555c0c6817de16a0d346

*说明*:以太坊合并后分为两层

  • **执行层**(Execution Layer):处理交易和智能合约
  • **共识层**(Consensus Layer):PoS 共识和验证者管理

Tron 多端点支持

Tron网络提供三种不同的API接口:

端点类型 路径 用途 特点
JSON-RPC /jsonrpc 标准RPC调用 兼容以太坊RPC,通用接口
Wallet API /wallet 实时钱包操作 最新数据,适合发送交易
Wallet Solidity /walletsolidity 查询已确认数据 延迟约3秒,但数据稳定可靠

*使用建议*:

1
2
3
发送交易     → 使用 /wallet
查询余额/数据 → 使用 /walletsolidity(更可靠)
兼容性调用   → 使用 /jsonrpc

*权重分配*:

  • /jsonrpc - weight=20(标准接口)
  • /wallet - weight=18(实时操作)
  • /walletsolidity - weight=22(查询首选,最稳定)

节点提供商

Chainstack(付费)

*优势*:

  • ⚡ 高性能、低延迟
  • 🔒 专属资源
  • ✅ 稳定性高
  • 🌐 支持 HTTP + WebSocket

*配置*:

  • Priority: 1(最高)
  • Weight: 18-22(根据端点类型)
  • 支持链:
    • Arbitrum(HTTP + WS)
    • Solana(HTTP + WS)
    • BSC(HTTP + WS)
    • Ethereum(HTTP + WS + Beacon API)
    • Tron(JSON-RPC + Wallet + Wallet Solidity)

Infura(免费)

*优势*:

  • 🆓 免费额度
  • 📊 稳定性较好
  • 🌐 支持 HTTP + WebSocket
  • 🔧 易于使用

*限制*:

  • ⚠️ 有请求限流
  • ⚠️ 可能会有延迟

*配置*:

  • Priority: 2
  • Weight: 15
  • 支持链:Ethereum、Sepolia、BSC

公共RPC节点

*优势*:

  • 🆓 完全免费
  • 🌍 多个提供商

*限制*:

  • ⚠️ 可能不稳定
  • ⚠️ 可能有限流
  • ⚠️ 延迟可能较高

*配置*:

  • Priority: 3(最低)
  • Weight: 8-10
  • 作为备用节点

*提供商包括*:

  • LlamaNodes
  • Ankr
  • PublicNode
  • dRPC
  • 各链官方节点

节点优先级说明

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
选择流程:
1. 筛选所有健康节点(is_healthy = true)
2. 按 priority 分组(值越小优先级越高)
3. 选择最小 priority 的节点组
4. 在该组内根据 weight 进行加权随机选择
5. 如果该组所有节点都故障,降级到下一个 priority 组

示例:
- 如果 Chainstack 节点健康 → 100% 使用 Chainstack
- 如果 Chainstack 故障 → 自动切换到 Infura
- 如果 Infura 也故障 → 自动切换到公共节点

节点管理

添加自定义节点

通过 API 添加节点:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
curl -X POST http://localhost:8080/api/nodes \
  -H "Content-Type: application/json" \
  -d '{
    "chain_id": "ethereum",
    "http_url": "https://your-node.example.com",
    "ws_url": "wss://your-node.example.com",
    "provider": "YourProvider",
    "priority": 1,
    "weight": 20,
    "node_type": "both",
    "api_key_type": "bearer",
    "api_key": "your-api-key"
  }'

修改节点优先级

1
2
3
4
5
6
curl -X PUT http://localhost:8080/api/nodes/{id} \
  -H "Content-Type: application/json" \
  -d '{
    "priority": 1,
    "weight": 25
  }'

禁用节点

1
2
3
4
5
curl -X PUT http://localhost:8080/api/nodes/{id} \
  -H "Content-Type: application/json" \
  -d '{
    "is_active": false
  }'

查看节点状态

1
2
3
4
5
6
7
8
# 查看所有节点
curl http://localhost:8080/api/nodes

# 查看特定链的节点
curl http://localhost:8080/api/nodes?chain_id=ethereum

# 只看健康节点
curl http://localhost:8080/api/nodes?is_healthy=true

节点健康监控

系统会自动:

  • 每30秒检查一次节点健康状态
  • 记录响应时间(avg_response_time)
  • 统计连续失败次数
  • 自动识别并处理错误类型(链ID不匹配、认证失败、限流等)
  • 达到阈值后自动禁用节点

API文档

所有管理接口返回统一格式:

1
2
3
4
5
{
  "code": 0,      // 0成功,1失败
  "msg": "success",
  "data": {}      // 业务数据
}

RPC代理接口

POST /{chain_id}

在专用域名 crpc.coinexus.life 下,按链ID挂在根路径,例如:

  • Ethereum: POST https://crpc.coinexus.life/ethereum
  • BSC: POST https://crpc.coinexus.life/bsc
  • Arbitrum: POST https://crpc.coinexus.life/arbitrum
  • Solana: POST https://crpc.coinexus.life/solana

转发RPC请求到该链的健康节点。支持 单个请求 和 *批量请求*(JSON-RPC 2.0 规范)。

  • 支持链与请求地址一览

    统一规则:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    
    # ========== 主流 EVM 链 ==========
    ethereum          以太坊主网
      https://crpc.coinexus.life/ethereum
    
    sepolia           以太坊 Sepolia 测试网
      https://crpc.coinexus.life/sepolia
    
    goerli            以太坊 Goerli 测试网
      https://crpc.coinexus.life/goerli
    
    bsc               BNB Smart Chain 主网
      https://crpc.coinexus.life/bsc
    
    bsc-testnet       BSC 测试网
      https://crpc.coinexus.life/bsc-testnet
    
    polygon           Polygon 主网
      https://crpc.coinexus.life/polygon
    
    polygon-mumbai    Polygon Mumbai 测试网
      https://crpc.coinexus.life/polygon-mumbai
    
    polygon-zkevm     Polygon zkEVM 主网
      https://crpc.coinexus.life/polygon-zkevm
    
    avalanche         Avalanche C-Chain 主网
      https://crpc.coinexus.life/avalanche
    
    fantom            Fantom Opera 主网
      https://crpc.coinexus.life/fantom
    
    cronos            Cronos 主网
      https://crpc.coinexus.life/cronos
    
    # ========== Layer 2 / Rollup ==========
    arbitrum          Arbitrum One 主网
      https://crpc.coinexus.life/arbitrum
    
    arbitrum-sepolia  Arbitrum Sepolia 测试网
      https://crpc.coinexus.life/arbitrum-sepolia
    
    optimism          Optimism 主网
      https://crpc.coinexus.life/optimism
    
    base              Coinbase Base 主网
      https://crpc.coinexus.life/base
    
    zksync            zkSync Era 主网
      https://crpc.coinexus.life/zksync
    
    # ========== 非 EVM 链 ==========
    solana            Solana 主网
      https://crpc.coinexus.life/solana
    
    solana-testnet    Solana Testnet
      https://crpc.coinexus.life/solana-testnet
    
    solana-devnet     Solana Devnet
      https://crpc.coinexus.life/solana-devnet
    
    tron              Tron 主网(Chainstack JSON-RPC / Wallet / Solidity 端)
      https://crpc.coinexus.life/tron
    
  • 单个请求

    最常见的RPC调用方式。

    *请求示例*:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    POST /ethereum
    Content-Type: application/json
    
    {
      "jsonrpc": "2.0",
      "method": "eth_blockNumber",
      "params": [],
      "id": 1
    }
    

    *响应示例*:

    1
    2
    3
    4
    5
    
    {
      "jsonrpc": "2.0",
      "result": "0x1234567",
      "id": 1
    }
    
  • 批量请求(Batch Request)

    ✅ CRPC 完全支持 JSON-RPC 2.0 批量请求规范,与所有主流RPC客户端库兼容(ethers.js, web3.js, viem等)。

    **优势**:

    • 🚀 *性能提升*:1次网络往返完成多个RPC调用,延迟降低60-80%
    • ⚡ *并发处理*:CRPC内部并发转发批量请求中的每个调用,充分利用多核CPU
    • 💰 *节省成本*:减少HTTP连接数和网络开销
    • 🔧 *标准兼容*:符合JSON-RPC 2.0规范,所有上游节点都支持

    **批量请求示例**:

    1
    2
    3
    4
    5
    6
    7
    8
    
    POST /ethereum
    Content-Type: application/json
    
    [
      {"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]},
      {"jsonrpc":"2.0","id":2,"method":"eth_gasPrice","params":[]},
      {"jsonrpc":"2.0","id":3,"method":"eth_chainId","params":[]}
    ]
    

    **批量响应示例**:

    1
    2
    3
    4
    5
    
    [
      {"jsonrpc":"2.0","id":1,"result":"0x1234567"},
      {"jsonrpc":"2.0","id":2,"result":"0x3b9aca00"},
      {"jsonrpc":"2.0","id":3,"result":"0x1"}
    ]
    

    **批量账户余额查询示例**:

    1
    2
    3
    4
    5
    
    [
      {"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045","latest"]},
      {"jsonrpc":"2.0","id":2,"method":"eth_getBalance","params":["0x8B3192f5eEBD8579568A2Ed41E6FEB402f93f73F","latest"]},
      {"jsonrpc":"2.0","id":3,"method":"eth_getBalance","params":["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb","latest"]}
    ]
    

    **批量请求限制**:

    为防止恶意超大批量请求,CRPC设置了批量请求大小限制:

    配置项 默认值 说明
    max_batch_size 100 单次批量请求最大调用数

    超过限制的请求将返回错误:

    1
    2
    3
    4
    5
    
    {
      "code": 1,
      "msg": "批量请求数量超过限制 (最大: 100, 实际: 150)",
      "data": null
    }
    

    **使用场景**:

    场景 说明 示例
    网络检测 ethers.js初始化时自动发送批量请求检测网络 eth_chainId + net_version
    批量查询余额 一次查询多个钱包地址的余额 多个 eth_getBalance
    数据聚合 获取多种链上数据(区块、Gas价格、Nonce等) eth_blockNumber + eth_gasPrice + eth_getTransactionCount
    批量读取交易 一次获取多笔交易详情 多个 eth_getTransactionByHash

    **测试批量请求**:

    1
    2
    3
    
    # 运行批量请求测试脚本
    cd /home/smokey/Desktop/crpc
    ./scripts/test_batch_requests.sh
    

    该脚本会测试:

    • ✅ 小型批量(2个):网络检测
    • ✅ 中型批量(5个):多个只读查询
    • ✅ 批量余额查询(10个地址)
    • ✅ 混合查询(不同方法)
    • ✅ 大批量(20个):压力测试
    • ✅ 超大批量(150个):限流测试
    • ✅ 性能对比:批量 vs 单个请求

管理接口

GET /health

健康检查接口。

*响应示例*:

1
2
3
4
{
  "status": "ok",
  "instance_id": "crpc-1"
}

GET /api/chains

获取所有链列表。

GET /api/chains/{chain_id}

获取单个链信息。

GET /api/nodes

获取节点列表。

*查询参数*:

  • chain_id:可选,筛选指定链的节点

GET /api/nodes/{id}

获取单个节点详情。

POST /api/nodes

创建新节点。

*请求体*:

1
2
3
4
5
6
7
8
{
  "chain_id": "ethereum",
  "node_url": "https://rpc.example.com",
  "provider": "Example",
  "priority": 10,
  "weight": 5,
  "is_active": true
}

PUT /api/nodes/{id}

更新节点信息。

*请求体*:

1
2
3
4
5
{
  "priority": 5,
  "weight": 10,
  "is_active": false
}

DELETE /api/nodes/{id}

删除节点。

GET /api/stats/nodes

获取节点统计信息。

*响应示例*:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
  "code": 0,
  "msg": "success",
  "data": {
    "ethereum": {
      "total": 3,
      "healthy": 2
    },
    "bsc": {
      "total": 2,
      "healthy": 2
    }
  }
}

配置说明

config.toml 详解

配置文件位于 config/config.toml

Server配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
[server]
port = 8080              # HTTP服务端口
mode = "release"         # 运行模式: debug, release
read_timeout = 30        # 读取超时(秒)
write_timeout = 30       # 写入超时(秒)
instance_id = "crpc-1"   # 实例ID,多实例需不同

# 监听模式配置(新增)
enable_http = true       # 是否启用HTTP监听(TCP)
enable_socket = false    # 是否启用Unix Socket监听
# ⚠️ 开发环境示例:可以使用/tmp,便于本机调试
#    socket_path = "/tmp/crpc.sock"  # 开发环境示例
# 生产环境请避免使用/tmp(Nginx通常启用PrivateTmp=true,看不到/tmp里的socket)
# 推荐放在服务目录或/run下,例如:
#    socket_path = "/srv/crpc/crpc.sock"
#    socket_path = "/run/crpc.sock"
socket_path = "/tmp/crpc.sock"  # 默认值(开发环境友好),生产环境请按上面说明修改

*多实例配置*:

  • 可通过环境变量 CRPC_INSTANCE_ID 覆盖 instance_id
  • 每个实例必须使用不同的端口和ID(HTTP模式)
  • 每个实例必须使用不同的socket路径(Socket模式)

*监听模式选择*:

  • enable_http = true, enable_socket = false:仅HTTP(跨服务器)
  • enable_http = false, enable_socket = true:仅Socket(同服务器,推荐)
  • enable_http = true, enable_socket = true:双监听(最大灵活性)
  • 至少需要启用一种模式

Database配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[database]
host = "localhost"
port = 5432
user = "crpc"
password = "crpc_password"
dbname = "crpc"
sslmode = "disable"
max_open_conns = 25      # 最大打开连接数
max_idle_conns = 5       # 最大空闲连接数
conn_max_lifetime = 300  # 连接最大生命周期(秒)

健康检查配置

1
2
3
4
5
6
[health_check]
enabled = true           # 是否启用健康检查
interval = 10            # 检查间隔(秒)
timeout = 5              # RPC请求超时(秒)
max_failures = 3         # 连续失败次数阈值
recovery_interval = 30   # 不健康节点重新检查间隔(秒)

代理配置

1
2
3
4
5
6
[proxy]
retry_count = 2          # 失败重试次数
request_timeout = 30     # 请求超时(秒)
enable_cache = false     # 是否启用缓存(未实现)
cache_ttl = 60           # 缓存TTL(秒)
max_batch_size = 100     # 批量请求最大数量(防止恶意超大批量请求)

*说明*:

  • max_batch_size:限制单次批量请求(Batch Request)的最大调用数
  • 超过此限制的批量请求将被拒绝并返回错误
  • 默认值100对大多数场景足够,可根据实际需求调整
  • 设置为0表示使用默认值100

日志配置

1
2
3
4
[log]
level = "info"           # 日志级别: debug, info, warn, error
output = "stdout"        # 输出位置: stdout, file
file_path = "../log/crpc.log"  # 日志文件路径

日志清理配置

1
2
3
4
[log_cleanup]
enabled = true          # 是否启用自动清理
interval = 24           # 清理间隔(小时),默认每24小时
retention_days = 7      # 日志保留天数,删除N天前的日志

*说明*:

  • 应用启动时自动开始清理任务
  • 清理任务在后台运行,不影响主服务
  • 可通过API手动触发清理: POST /api/logs/cleanup
  • 可通过API查看日志统计: GET /api/stats/logs
  • 无需重启PostgreSQL数据库

数据库Schema

数据库Schema定义在 migration/001_init_schema.sql

主要表结构

*chains表*:链信息

  • chain_id:链ID(如ethereum、bsc)
  • chain_name:链名称
  • description:描述

*rpc_nodes表*:RPC节点配置

  • chain_id:所属链
  • node_url:节点URL
  • provider:提供商
  • priority:优先级(数字越小优先级越高)
  • weight:负载均衡权重
  • is_active:是否启用
  • is_healthy:是否健康
  • failure_count:连续失败次数
  • success_count:成功次数
  • avg_response_time:平均响应时间(毫秒)

*health_check_logs表*:健康检查日志

  • node_id:节点ID
  • is_healthy:检查结果
  • response_time:响应时间
  • error_message:错误信息
  • checked_by:检查的实例ID

*request_logs表*:请求日志(可选)

  • chain_id:链ID
  • node_id:使用的节点
  • method:RPC方法
  • success:是否成功
  • response_time:响应时间
  • instance_id:处理请求的实例ID

部署指南

生产环境部署(使用Systemd)

1. 准备环境

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 创建部署目录
sudo mkdir -p /opt/crpc
sudo chown $USER:$USER /opt/crpc

# 复制项目文件
cp -r /home/smokey/Desktop/crpc/* /opt/crpc/

# 编译程序
cd /opt/crpc
make build

2. 创建Systemd服务

创建 /etc/systemd/system/crpc@.service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Unit]
Description=CRPC Instance %i
After=network.target postgresql.service

[Service]
Type=simple
User=crpc
WorkingDirectory=/opt/crpc/program
Environment="CRPC_INSTANCE_ID=crpc-%i"
ExecStart=/opt/crpc/program/crpc
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

3. 创建配置文件

为每个实例创建配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 实例1(端口8080)
cp /opt/crpc/config/config.toml /opt/crpc/config/config.instance1.toml

# 实例2(端口8081)
cp /opt/crpc/config/config.toml /opt/crpc/config/config.instance2.toml
sed -i 's/port = 8080/port = 8081/' /opt/crpc/config/config.instance2.toml
sed -i 's/instance_id = "crpc-1"/instance_id = "crpc-2"/' /opt/crpc/config/config.instance2.toml

# 实例3(端口8082)
cp /opt/crpc/config/config.toml /opt/crpc/config/config.instance3.toml
sed -i 's/port = 8080/port = 8082/' /opt/crpc/config/config.instance3.toml
sed -i 's/instance_id = "crpc-1"/instance_id = "crpc-3"/' /opt/crpc/config/config.instance3.toml

4. 启动服务

1
2
3
4
5
6
7
8
9
# 启动实例
sudo systemctl enable crpc@1 crpc@2 crpc@3
sudo systemctl start crpc@1 crpc@2 crpc@3

# 查看状态
sudo systemctl status crpc@*

# 查看日志
sudo journalctl -u crpc@1 -f

5. 配置Nginx

1
2
3
4
5
6
7
8
9
# 复制Nginx配置
sudo cp /opt/crpc/config/nginx.conf /etc/nginx/nginx.conf

# 测试配置
sudo nginx -t

# 重启Nginx
sudo systemctl restart nginx
sudo systemctl enable nginx

添加新链

通过SQL添加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
-- 连接数据库
psql -h localhost -U crpc -d crpc

-- 添加新链
INSERT INTO chains (chain_id, chain_name, description)
VALUES ('arbitrum', 'Arbitrum One', 'Arbitrum Layer 2网络');

-- 添加节点
INSERT INTO rpc_nodes (chain_id, node_url, provider, priority, weight)
VALUES
('arbitrum', 'https://arb1.arbitrum.io/rpc', 'Official', 1, 10),
('arbitrum', 'https://rpc.ankr.com/arbitrum', 'Ankr', 2, 10),
('arbitrum', 'https://arbitrum.llamarpc.com', 'LlamaNodes', 3, 5);

通过API添加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 先手动添加链到数据库,然后通过API添加节点
curl -X POST http://localhost/api/nodes \
  -H "Content-Type: application/json" \
  -d '{
    "chain_id": "arbitrum",
    "node_url": "https://arb1.arbitrum.io/rpc",
    "provider": "Official",
    "priority": 1,
    "weight": 10,
    "is_active": true
  }'

自动化部署脚本

项目提供了三个自动化部署脚本,简化生产环境部署:

1. 单实例远程部署 (deploy_to_remote.sh)

快速编译并部署单实例到远程服务器:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
cd scripts

# 部署到默认服务器(d1.smokey)
./deploy_to_remote.sh

# 脚本会自动:
# 1. 本地编译应用
# 2. 上传二进制文件到远程服务器
# 3. 询问是否更新配置文件
# 4. 重启远程服务
# 5. 验证服务健康状态

*适用场景*:

  • 开发测试环境
  • 单服务器小规模部署
  • 快速迭代和调试

2. 多实例远程部署 (deploy_multi_instance.sh)

一键在远程服务器部署多个CRPC实例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
cd scripts

# 部署3个实例到 d1.smokey(默认)
./deploy_multi_instance.sh

# 部署5个实例到指定服务器
./deploy_multi_instance.sh your-server 5

# 脚本会自动:
# 1. 编译应用程序
# 2. 上传二进制文件
# 3. 为每个实例生成独立配置(端口 8080-808N)
# 4. 创建 systemd 服务单元 (crpc@1, crpc@2, ...)
# 5. 更新 Nginx 负载均衡配置
# 6. 启动所有实例并验证

*生成的服务*:

  • crpc@1.service (端口 8080)
  • crpc@2.service (端口 8081)
  • crpc@3.service (端口 8082)

*管理命令*:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 查看所有实例状态
ssh d1.smokey systemctl status 'crpc@*'

# 重启所有实例
ssh d1.smokey systemctl restart 'crpc@*'

# 停止单个实例
ssh d1.smokey systemctl stop crpc@2

# 查看实例日志
ssh d1.smokey journalctl -u crpc@1 -f

*适用场景*:

  • 生产环境高可用部署
  • 需要负载均衡的场景
  • 服务器资源充足(多核CPU)

3. 性能基准测试 (benchmark.sh)

全面测试CRPC服务性能:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
cd scripts

# 测试默认服务器(192.168.1.21)
./benchmark.sh

# 测试指定地址,10并发,100请求
./benchmark.sh http://your-server 10 100

# 测试内容包括:
# 1. 健康检查端点延迟测试
# 2. RPC代理响应时间测试(eth_blockNumber)
# 3. API管理接口功能测试
# 4. 负载均衡验证(实例分配统计)
# 5. 并发压力测试(需要 ab 工具)
# 6. 节点和日志统计信息

*典型输出*:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
============================================
📊 CRPC 性能测试
============================================
目标地址: http://192.168.1.21
并发数: 10
请求数: 100
============================================

测试1: 健康检查端点
GET http://192.168.1.21/health
  请求 1: {"instance_id":"crpc-1","status":"ok"} (耗时: 0.001ms)
  ...

测试2: RPC代理 - eth_blockNumber
  ✅ 请求 1: 成功 - 区块高度 0x16b77f2 (耗时: 0.5s)
  ...
  统计结果:
    成功: 20
    失败: 0
    平均响应时间: 0.45s

测试4: 负载均衡测试
  实例分配统计:
    crpc-1: 4 次请求
    crpc-2: 3 次请求
    crpc-3: 3 次请求

4. 实时监控面板 (monitor.sh)

实时监控CRPC服务运行状态:

1
2
3
4
5
6
7
8
9
cd scripts

# 监控默认服务器,每5秒刷新
./monitor.sh

# 监控指定服务器,每3秒刷新
./monitor.sh your-server 3

# 按 Ctrl+C 退出监控

*监控内容*:

  1. 🔧 *服务状态*:所有CRPC实例运行状态
  2. 🏥 *健康检查*:Nginx代理健康状态
  3. 🌐 *RPC节点统计*:总节点、健康节点、异常节点数量
  4. 📝 *日志统计*:请求日志、健康检查日志数量
  5. 🚦 *Nginx状态*:活跃连接、总请求数
  6. 💻 *系统资源*:CPU、内存、磁盘使用情况
  7. 🚨 *错误日志*:最近5分钟的错误(如有)

*监控面板示例*:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
============================================
📊 CRPC 服务监控面板
============================================
主机: d1.smokey
刷新间隔: 5s
时间: 2025-11-17 19:30:45
============================================

🔧 服务状态
----------------------------------------
crpc@1.service: ✅ 运行中
crpc@2.service: ✅ 运行中
crpc@3.service: ✅ 运行中

🏥 健康检查
----------------------------------------
Nginx 代理: ✅ 正常
响应: {"instance_id":"crpc-2","status":"ok"}

🌐 RPC 节点统计
----------------------------------------
  总节点数: 15
  健康节点: 13
  异常节点: 2

💻 系统资源
----------------------------------------
  CPU 使用率: 8.5%
  内存: 已用: 1850MB / 总计: 3950MB (46.8%)
  磁盘: 已用: 12.5G / 总计: 50G (26%)

部署流程建议

*初次部署生产环境*:

1
2
3
4
5
6
7
8
9
# 步骤1:部署多实例
cd scripts
./deploy_multi_instance.sh your-server 3

# 步骤2:运行性能测试
./benchmark.sh http://your-server

# 步骤3:启动实时监控(另开终端)
./monitor.sh your-server 5

*日常更新*:

1
2
3
# 快速重新部署(已配置好systemd和Nginx)
cd scripts
./deploy_to_remote.sh

监控和运维

健康检查

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 检查Nginx状态
curl http://localhost/health

# 检查特定实例(直连)
curl http://localhost:8080/health
curl http://localhost:8081/health
curl http://localhost:8082/health

# 检查所有实例
for i in 8080 8081 8082; do
  echo "实例端口$i:"
  curl -s http://localhost:$i/health | jq
done

日志查看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 本地运行
tail -f log/crpc.log

# Systemd管理的服务
sudo journalctl -u crpc@1 -f
sudo journalctl -u crpc@2 -f
sudo journalctl -u crpc@3 -f

# 查看所有实例日志
sudo journalctl -u 'crpc@*' -f

数据库监控

查看节点健康状态

1
2
3
4
5
6
7
8
SELECT
    chain_id,
    COUNT(*) as total,
    SUM(CASE WHEN is_healthy THEN 1 ELSE 0 END) as healthy,
    SUM(CASE WHEN is_healthy THEN 0 ELSE 1 END) as unhealthy
FROM rpc_nodes
WHERE is_active = true
GROUP BY chain_id;

查看最近的健康检查日志

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
SELECT
    n.chain_id,
    n.node_url,
    h.is_healthy,
    h.response_time,
    h.checked_by,
    h.checked_at
FROM health_check_logs h
JOIN rpc_nodes n ON h.node_id = n.id
ORDER BY h.checked_at DESC
LIMIT 20;

查看请求统计

1
2
3
4
5
6
7
8
SELECT
    chain_id,
    COUNT(*) as total_requests,
    SUM(CASE WHEN success THEN 1 ELSE 0 END) as success_count,
    AVG(response_time) as avg_response_time
FROM request_logs
WHERE created_at > NOW() - INTERVAL '1 hour'
GROUP BY chain_id;

日志管理与自动清理

系统提供了**应用内置的自动清理功能**,无需安装额外的PostgreSQL扩展,也**无需重启数据库**。

应用内置自动清理(推荐✅)

CRPC应用内置了后台定时清理任务,自动管理日志数据。

  • 配置说明

    config/config.toml 中配置:

    1
    2
    3
    4
    
    [log_cleanup]
    enabled = true  # 是否启用自动清理
    interval = 24   # 小时,清理任务执行间隔(默认每24小时)
    retention_days = 7  # 保留天数,删除N天前的日志
    
  • 工作原理

    • ✅ 应用启动时,自动创建后台清理任务
    • ✅ 按配置的间隔(默认24小时)自动执行清理
    • ✅ 应用停止时,清理任务自动停止
    • ✅ 完全在Go应用内部实现,无需外部依赖
    • ✅ 不需要重启PostgreSQL数据库
  • API接口

    **查看日志统计**:

    1
    
    curl http://localhost:8080/api/stats/logs
    

    返回示例:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    {
      "code": 0,
      "msg": "success",
      "data": {
        "request_logs_count": 12345,
        "health_check_logs_count": 67890,
        "oldest_request_log": "2024-11-10T10:30:00Z",
        "oldest_health_log": "2024-11-10T10:30:00Z"
      }
    }
    

    **手动触发清理**:

    1
    
    curl -X POST http://localhost:8080/api/logs/cleanup
    
  • 优点
    特性 说明
    ✅ 无需外部依赖 不需要安装pg_cron扩展
    ✅ 无需重启数据库 不影响生产环境其他服务
    ✅ 易于管理 通过配置文件控制
    ✅ 自动启停 跟随应用生命周期
    ✅ 日志可见 清理过程记录在应用日志中
    ✅ API支持 可手动触发和查看统计

监控日志增长

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
-- 查看表大小和行数
SELECT
    schemaname,
    tablename,
    pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size,
    n_live_tup AS row_count
FROM pg_stat_user_tables
WHERE tablename IN ('request_logs', 'health_check_logs')
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;

-- 查看每天的日志增长
SELECT
    DATE(created_at) as date,
    COUNT(*) as request_count
FROM request_logs
WHERE created_at > NOW() - INTERVAL '30 days'
GROUP BY DATE(created_at)
ORDER BY date DESC;

性能优化

数据库优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
-- 定期清理旧日志(保留7天)
DELETE FROM health_check_logs WHERE checked_at < NOW() - INTERVAL '7 days';
DELETE FROM request_logs WHERE created_at < NOW() - INTERVAL '7 days';

-- 创建定时任务
CREATE EXTENSION IF NOT EXISTS pg_cron;

SELECT cron.schedule(
    'cleanup-old-logs',
    '0 2 * * *',  -- 每天凌晨2点
    $$
    DELETE FROM health_check_logs WHERE checked_at < NOW() - INTERVAL '7 days';
    DELETE FROM request_logs WHERE created_at < NOW() - INTERVAL '7 days';
    $$
);

禁用请求日志(可选)

如果不需要详细的请求日志,可以注释掉代码中的日志记录:

1
2
# 编辑 program/proxy/proxy.go
# 注释掉 CreateRequestLog 相关调用

Nginx优化

编辑 config/nginx.conf

1
2
3
4
5
6
7
8
# 增加worker进程
worker_processes auto;

# 增加keepalive连接
keepalive 64;

# 增加连接超时
keepalive_timeout 65;

故障排查

实例无法启动

检查配置文件

1
2
3
cd program
./crpc
# 查看错误信息

检查数据库连接

1
psql -h localhost -U crpc -d crpc -c "SELECT 1;"

检查端口占用

1
2
3
4
# 检查端口是否被占用
netstat -tunlp | grep 8080
netstat -tunlp | grep 8081
netstat -tunlp | grep 8082

节点始终不健康

查看节点详情

1
SELECT * FROM rpc_nodes WHERE id = 1;

查看健康检查日志

1
2
3
4
SELECT * FROM health_check_logs
WHERE node_id = 1
ORDER BY checked_at DESC
LIMIT 10;

手动测试节点

1
2
3
curl -X POST https://eth.llamarpc.com \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

手动重置节点状态

1
2
3
UPDATE rpc_nodes
SET is_healthy = true, failure_count = 0
WHERE id = 1;

负载不均衡

检查Nginx配置

1
2
sudo nginx -t
curl http://localhost/nginx_status

检查实例运行状态

1
2
3
4
5
# Systemd
sudo systemctl status crpc@1 crpc@2 crpc@3

# 直接检查进程
ps aux | grep crpc

查看请求分布

1
2
3
4
5
6
SELECT
    instance_id,
    COUNT(*) as request_count
FROM request_logs
WHERE created_at > NOW() - INTERVAL '1 hour'
GROUP BY instance_id;

数据库连接池耗尽

如果看到 “too many connections” 错误:

1
2
3
4
# 编辑 config/config.toml
[database]
max_open_conns = 50  # 增加最大连接数
max_idle_conns = 10  # 增加空闲连接数

常见问题

Q: 如何实现零停机更新?

A: 使用滚动更新策略:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 1. 更新实例1
sudo systemctl stop crpc@1
cd /opt/crpc/program
go build -o crpc .
sudo systemctl start crpc@1
sleep 10  # 等待健康检查通过

# 2. 更新实例2
sudo systemctl stop crpc@2
sudo systemctl start crpc@2
sleep 10

# 3. 更新实例3
sudo systemctl stop crpc@3
sudo systemctl start crpc@3

Nginx会自动将流量切到健康实例。

Q: 实例数量如何选择?

A: 根据请求量选择:

  • 低流量(<1000 req/s):2-3个实例
  • 中流量(1000-5000 req/s):3-5个实例
  • 高流量(>5000 req/s):5+个实例

建议至少3个实例保证高可用。

Q: 数据库会成为瓶颈吗?

A: 当前设计下,数据库压力很小:

  • 读操作:每个RPC请求查询一次节点列表(可以加索引)
  • 写操作:健康检查每10秒一次

如果成为瓶颈,可以:

  • 增加数据库连接池
  • 使用PostgreSQL只读从库(读写分离)
  • 添加Redis缓存层
  • 定期清理历史日志

Q: 如何跨数据中心部署?

A: 可以在每个数据中心部署独立的CRPC集群:

  1. 每个数据中心独立的CRPC实例 + PostgreSQL
  2. 数据库使用主从复制或多主复制同步配置
  3. 使用全局负载均衡器(CloudFlare、AWS Route53)分发流量
  4. 每个集群独立运行健康检查

Q: 如何添加认证?

A: 可以在API层添加中间件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// program/api/handler.go
func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("X-API-Key")
        if token == "" || !validateToken(token) {
            c.JSON(401, gin.H{"error": "Unauthorized"})
            c.Abort()
            return
        }
        c.Next()
    }
}

// 在SetupRoutes中使用
api := r.Group("/api")
api.Use(AuthMiddleware())
{
    // ... 路由定义
}

Q: 如何监控节点的实时状态?

A: 创建一个监控脚本:

1
2
3
#!/bin/bash
# 每5秒刷新一次节点状态
watch -n 5 "curl -s http://localhost/api/stats/nodes | jq"

或者集成Prometheus + Grafana(未来实现)。

Q: 某个节点经常不稳定怎么办?

A: 几个处理方法:

  1. 降低该节点的优先级:
1
2
3
curl -X PUT http://localhost/api/nodes/{id} \
  -H "Content-Type: application/json" \
  -d '{"priority": 99, "weight": 1}'
  1. 临时禁用该节点:
1
2
3
curl -X PUT http://localhost/api/nodes/{id} \
  -H "Content-Type: application/json" \
  -d '{"is_active": false}'
  1. 更换为其他RPC提供商的节点

性能指标

单实例性能

  • RPC请求:~1000-5000 req/s
  • 数据库连接:25个(可调整)
  • 内存占用:~50-100MB
  • CPU占用:~10-30%(取决于请求量)

3实例集群

  • 总吞吐:~3000-15000 req/s
  • 高可用:任意1个实例宕机不影响服务
  • 数据库压力:很小(读多写少)

响应时间

  • 健康检查:~1ms (Nginx本地代理)
  • RPC转发:+10-50ms(取决于后端RPC节点)
  • API管理接口:<100ms

性能测试结果

基于 d1.smokey (192.168.1.21) 的实际测试结果:

健康检查性能

  • 延迟:**0.7-1.2ms** (通过Nginx代理)
  • 稳定性:100% 成功率
  • 吞吐:>10000 req/s

RPC代理性能

  • 首次请求:~9s(健康检查初始化)
  • 后续请求:~0.5-2s(取决于上游节点)
  • 成功率:>95%(取决于上游节点健康度)

资源消耗

  • 单实例内存:~50MB
  • 单实例CPU:<5%(空闲)、10-30%(负载)

性能优化措施

本项目已实施以下性能优化:

1. Nginx层优化

连接池 (keepalive)

1
2
3
upstream crpc_backend {
    keepalive 64;  # 保持64个长连接到后端
}
  • ✅ 减少TCP握手开销
  • ✅ 提升吞吐量

Gzip压缩

1
2
3
gzip on;
gzip_comp_level 6;
gzip_types application/json;
  • ✅ 减少网络传输量(JSON响应压缩 ~70%)
  • ✅ 适合API和RPC响应

请求缓冲优化

1
2
3
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 8 8k;
  • ✅ 避免后端慢速影响Nginx
  • ✅ 支持大型RPC响应

负载均衡算法

1
2
3
4
upstream crpc_backend {
    least_conn;  # 最少连接算法
    server localhost:8080 max_fails=3 fail_timeout=30s;
}
  • ✅ 智能分配请求到最空闲实例
  • ✅ 自动故障转移(3次失败后30秒超时)

2. Go应用层优化

数据库连接池

1
2
3
4
[database]
max_open_conns = 50   # 最大连接数
max_idle_conns = 10   # 空闲连接池
conn_max_lifetime = 3600  # 连接复用时长(秒)
  • ✅ 避免频繁创建/销毁连接
  • ✅ 支持高并发查询

结构化日志 (zap)

  • ✅ 零内存分配日志
  • ✅ 比标准库快 10倍

HTTP/1.1 长连接

1
2
proxy_http_version 1.1;
proxy_set_header Connection "";
  • ✅ 复用HTTP连接到上游RPC节点
  • ✅ 减少握手延迟

3. 数据库优化

索引优化

1
2
3
4
5
6
7
8
9
-- 链ID索引(常用查询)
CREATE INDEX idx_nodes_chain ON rpc_nodes(chain_id);

-- 健康节点查询索引(组合索引)
CREATE INDEX idx_nodes_healthy ON rpc_nodes(chain_id, is_healthy, is_active);

-- 日志时间索引(清理操作)
CREATE INDEX idx_request_logs_time ON request_logs(created_at);
CREATE INDEX idx_health_logs_time ON health_check_logs(checked_at);

自动日志清理

  • ✅ 应用内置定时清理(避免PostgreSQL重启)
  • ✅ 保留7天日志(可配置)
  • ✅ 每24小时自动清理一次

4. 架构优化

多实例部署

  • ✅ 水平扩展能力(3实例 = 3倍吞吐量)
  • ✅ 高可用(单实例故障不影响服务)

健康检查与故障切换

  • ✅ 每30秒检查一次节点健康
  • ✅ 自动禁用故障节点
  • ✅ 故障节点恢复后自动启用

智能节点选择

  • ✅ 优先级 + 权重 + 平均响应时间
  • ✅ 自动避开慢速/故障节点
  • ✅ 支持多节点重试

5. 未来优化方向

缓存层

1
2
3
4
[计划中] 添加 Redis 缓存
- 缓存 eth_blockNumber 等轻量查询(5秒TTL)
- 缓存节点列表(减少数据库查询)
- 预期提升:50-100% 吞吐量

连接复用池

1
2
3
4
[计划中] 上游RPC节点连接池
- 预建立和复用HTTP/WebSocket连接
- 减少TLS握手延迟
- 预期提升:20-50ms 延迟降低

分布式追踪

1
2
3
4
[计划中] 集成 OpenTelemetry
- 端到端请求追踪
- 性能瓶颈分析
- 更精准的监控告警

安全建议

1. 数据库安全

  • 使用强密码
  • 限制数据库访问IP
  • 启用SSL连接
  • 定期备份

2. API安全

  • 添加认证中间件(JWT或API Key)
  • 配置CORS策略
  • 限制管理接口访问(内网或VPN)
  • 实现请求限流

3. 网络安全

  • 使用HTTPS(配置SSL证书)
  • 配置防火墙规则
  • 定期更新系统和依赖
  • 监控异常流量

4. 监控告警

  • 节点故障告警
  • 实例宕机告警
  • 数据库连接异常告警
  • 请求成功率监控

开发计划

已完成

  • 基础RPC代理功能
  • 健康检查机制
  • 多实例部署支持
  • 负载均衡
  • RESTful API管理接口
  • 自动故障切换
  • WebSocket支持(数据库层和代码框架)
  • API Key认证支持(URL内嵌 + Header传递)
  • 智能错误识别(链ID不匹配、认证失败、限流等)

计划中

  • WebSocket功能启用(代码已就绪,默认禁用)
  • 请求缓存(eth_blockNumber等)
  • API认证授权(JWT)
  • Prometheus指标导出
  • Grafana仪表盘
  • IP白名单/黑名单
  • 请求限流
  • 管理后台UI

下一步目标(按优先级)

  1. 性能与稳定性强化(已在生产上线的基础上迭代)

    • 针对高流量链(Ethereum / BSC / Arbitrum / Solana)做分链级别的健康检查参数调优(interval/timeout/recovery_interval),形成「稳健」和「激进」两套profile。
    • 引入共享HTTP Transport(连接池)并按上游提供商维度调节 MaxIdleConns / MaxIdleConnsPerHost,进一步降低跨国节点的建连开销。
    • 在请求日志与健康检查日志上增加可配置采样率,避免在极高QPS场景下数据库成为瓶颈。
  2. 可观测性与告警体系

    • 暴露基础 Prometheus 指标(请求次数、成功率、P95 延迟、各链/各节点健康数),为接入 Grafana 做准备。
    • 基于现有 SQL 视图(如 node_error_stats)整理一套「运维排查手册」,包括常用查询与典型异常模式(链ID不匹配、限流、认证失败等)。
    • 增加简单的「自检接口」,汇总关键健康信号(数据库连通、迁移是否完成、配置版本等),方便上层监控系统做探活。
  3. 安全加固(控制面)

    • 为 `/api/*` 管理接口增加轻量级认证(例如固定管理 Token 或 IP 白名单 + Token 双重保护),避免开放环境下被误用或扫到。
    • 在配置层支持「只读模式」,用于排查或第三方接入时禁止修改节点/链配置。
    • 为未来的 JWT / 更复杂的权限模型预留中间件结构,但暂不强推业务改造。
  4. 缓存与速率控制

    • 为只读、高频且容忍轻微陈旧的数据(如 eth_blockNumber、链ID、gasPrice 等)增加可选的短TTL缓存层(内存或 Redis),在不影响正确性的前提下减轻上游节点压力。
    • 在 CRPC 层面增加「软限流」能力(按来源IP/按链ID的QPS封顶),优先保护昂贵的付费节点不被突发流量打穿。
  5. WebSocket 与实时能力

    • 完成 WebSocket 路由的启用与生产级别配置示例(包含 Nginx 反向代理、资源上限、心跳/断线重连策略)。
    • 针对 Arbitrum / Ethereum / Solana 等链设计标准化的订阅模式(新区块、特定事件),并在文档中给出推荐使用场景。
  6. 开发者体验与运营

    • 基于现有 API 封装一个极简「管理面 CLI」(例如 `crpcctl`),支持常用操作:列链、列节点、禁用/启用节点、查看错误统计等。
    • 在 `README.org` 中补充「生产环境最佳实践」一节(包含 Nginx/系统参数/日志与备份建议),与当前的部署说明区分开。

WebSocket支持

CRPC已完成WebSocket支持的**数据库层和代码框架**,默认禁用,可按需启用。

当前状态

  • ✅ **数据库支持**:已添加 ws_urlnode_type 字段
  • ✅ **数据模型**:完整支持
  • ✅ **代码框架**:WebSocket代理模块已创建
  • ⏸️ **功能状态**:默认禁用(config.tomlwebsocket.enabled = false

快速启用

1
2
3
4
5
6
7
8
9
# 1. 运行WebSocket迁移
make migrate-ws

# 2. 启用配置(编辑 config/config.toml)
[websocket]
enabled = true

# 3. 重启服务
make build && make run

客户端使用

JavaScript/TypeScript (Ethers.js)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import { ethers } from 'ethers';

// HTTP Provider(查询操作)
const httpProvider = new ethers.JsonRpcProvider('http://localhost/ethereum');

// WebSocket Provider(订阅操作)
const wsProvider = new ethers.WebSocketProvider('ws://localhost/ws/ethereum');

// 1. 订阅新区块
wsProvider.on('block', (blockNumber) => {
  console.log('新区块:', blockNumber);
});

// 2. 监听智能合约事件
const contract = new ethers.Contract(contractAddress, abi, wsProvider);
contract.on('Transfer', (from, to, amount) => {
  console.log('转账:', from, '->', to, amount.toString());
});

Python (Web3.py)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from web3 import Web3
from web3.providers.websocket import WebsocketProvider

# 创建WebSocket连接
ws_provider = WebsocketProvider('ws://localhost/ws/ethereum')
w3 = Web3(ws_provider)

# 订阅新区块
def handle_block(block_hash):
    block = w3.eth.get_block(block_hash)
    print(f'新区块: {block.number}')

block_filter = w3.eth.filter('latest')
w3.eth.watch_filter(block_filter, handle_block)

WebSocket节点配置

Infura

1
2
3
4
5
6
INSERT INTO rpc_nodes (chain_id, http_url, ws_url, provider, priority, weight, node_type, api_key_type)
VALUES
('ethereum',
 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID',
 'wss://mainnet.infura.io/ws/v3/YOUR_PROJECT_ID',
 'Infura', 1, 15, 'both', 'none');

Alchemy

1
2
3
4
5
6
INSERT INTO rpc_nodes (chain_id, http_url, ws_url, provider, priority, weight, node_type, api_key_type)
VALUES
('ethereum',
 'https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY',
 'wss://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY',
 'Alchemy', 1, 15, 'both', 'none');

node_type 字段说明

说明 http_url ws_url
http 仅支持HTTP 必填 可选
ws 仅支持WebSocket 可选 必填
both 两者都支持(推荐) 必填 必填

API Key 支持

CRPC **完全兼容**两种主流的API Key使用方式,无论你的RPC提供商使用哪种方式,都能无缝支持。

支持的认证方式

方式1:URL内嵌(最常见)

大多数公共RPC提供商(Infura、Alchemy、QuickNode等)将API Key直接嵌入URL中。

1
2
3
4
5
-- 示例:Infura
INSERT INTO rpc_nodes (chain_id, http_url, provider, api_key_type)
VALUES ('ethereum',
        'https://mainnet.infura.io/v3/YOUR_PROJECT_ID',
        'Infura', 'none');

**特点**:

  • ✅ API Key在URL中
  • ✅ 设置 api_key_type = 'none'
  • ✅ 无需额外配置
  • ✅ 向后兼容(原有配置继续工作)

方式2:HTTP Header传递

某些企业级或私有RPC服务要求通过HTTP Header传递API Key。

(a) Authorization Bearer 格式

1
2
3
4
INSERT INTO rpc_nodes (chain_id, http_url, provider, api_key_type, api_key)
VALUES ('ethereum',
        'https://api.example.com/eth',
        'Enterprise', 'header', 'your-secret-token');

发送的HTTP请求:

1
2
3
POST /eth HTTP/1.1
Authorization: Bearer your-secret-token  ← 自动添加
Content-Type: application/json

(b) 自定义Header(如X-API-Key)

1
2
3
4
5
6
7
8
INSERT INTO rpc_nodes (
    chain_id, http_url, provider,
    api_key_type, api_key, custom_header_name
) VALUES (
    'ethereum',
    'https://rpc.custom.com',
    'Custom', 'custom', 'your-api-key', 'X-API-Key'
);

发送的HTTP请求:

1
2
3
POST / HTTP/1.1
X-API-Key: your-api-key  ← 自动添加
Content-Type: application/json

快速启用

1
2
3
4
5
6
7
8
# 1. 运行数据库迁移
make migrate-apikey

# 2. 配置节点(根据提供商要求选择方式)
# 详见下面的示例或 API_KEY_GUIDE.org

# 3. 重启服务(自动生效)
make build && make run

常见RPC提供商配置

Infura(URL内嵌)

1
2
3
4
5
INSERT INTO rpc_nodes (chain_id, http_url, ws_url, provider, priority, weight, node_type, api_key_type)
VALUES ('ethereum',
        'https://mainnet.infura.io/v3/YOUR_PROJECT_ID',
        'wss://mainnet.infura.io/ws/v3/YOUR_PROJECT_ID',
        'Infura', 1, 15, 'both', 'none');

Alchemy(URL内嵌)

1
2
3
4
5
INSERT INTO rpc_nodes (chain_id, http_url, ws_url, provider, priority, weight, node_type, api_key_type)
VALUES ('ethereum',
        'https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY',
        'wss://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY',
        'Alchemy', 1, 15, 'both', 'none');

企业私有RPC(Header认证)

1
2
3
4
INSERT INTO rpc_nodes (chain_id, http_url, provider, priority, weight, api_key_type, api_key)
VALUES ('ethereum',
        'https://enterprise-rpc.company.com',
        'Private', 1, 20, 'header', 'enterprise_secret_token');

数据库字段说明

字段 类型 说明 示例
api_key VARCHAR(500) API密钥(敏感) ‘your-secret-key’
api_key_type VARCHAR(20) 认证类型 ’none’, ‘header’, ‘custom’
custom_header_name VARCHAR(100) 自定义Header名称 ‘X-API-Key’

安全特性

  1. ✅ **API Key不对外暴露**:API响应中不会返回 api_key 字段
  2. ✅ **日志脱敏**:日志中不记录API Key原文
  3. ✅ **灵活配置**:支持混合使用不同认证方式的节点
  4. ✅ **自动处理**:健康检查和请求转发自动添加正确的认证Header

测试验证

1
2
3
4
5
6
7
# 测试URL内嵌方式(Infura)
curl -X POST http://localhost/ethereum \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# 查看节点统计
curl http://localhost/api/stats/nodes

故障排查

API Key无效

1
2
3
4
-- 查看节点配置
SELECT id, http_url, api_key_type,
       CASE WHEN api_key IS NULL THEN 'NULL' ELSE '***' END as api_key_status
FROM rpc_nodes WHERE id = 1;

Header名称错误

1
2
3
4
-- 更新为正确的Header名称
UPDATE rpc_nodes
SET custom_header_name = 'X-Correct-Header-Name'
WHERE id = 1;

智能错误识别

CRPC具备**智能错误识别和分类**能力,能够自动检测RPC节点返回的各种错误,并采取相应的处理策略。

核心能力

  • ✅ **自动识别链ID不匹配**:检测节点配置错误(如Arbitrum节点却要求Base链ID)
  • ✅ **错误自动分类**:认证失败、限流、超时、连接失败等
  • ✅ **致命错误自动切换**:遇到严重错误立即切换到其他健康节点
  • ✅ **详细错误统计**:记录每个节点的错误历史和类型分布
  • ✅ **自动禁用问题节点**:链ID不匹配次数 ≥ 5 次自动禁用

支持的错误类型

错误类别 说明 自动切换 典型场景
chain_mismatch 链ID不匹配 ✅ 是 ARB节点返回"invalid chain ID"
auth 认证失败 ✅ 是 API Key过期或错误
rate_limit 请求限流 ✅ 是 超过API配额
timeout 请求超时 ✅ 是 节点响应慢
connection 连接失败 ✅ 是 网络故障
invalid_param 参数错误 ❌ 否 客户端请求错误

快速启用

1
2
3
4
5
# 1. 运行数据库迁移
make migrate-chain-validation

# 2. 重启服务(自动生效)
make build && make run

实战示例

场景:链ID不匹配

你请求Arbitrum链,但Chainstack节点配置错误返回:

1
2
3
4
5
6
{
  "error": {
    "code": -32000,
    "message": "invalid chain ID"
  }
}

**CRPC的自动处理**:

1
2
3
4
5
1️⃣  识别错误类型:chain_mismatch(致命)
2️⃣  记录错误:chain_id_mismatch_count + 1
3️⃣  标记节点不健康:is_healthy = false
4️⃣  自动切换到其他节点(如Alchemy)
5️⃣  重试成功 → 返回给客户端

**日志输出**:

1
2
3
4
5
6
7
8
[ERROR] ⚠️  检测到链ID不匹配错误!
  node_id=5
  provider=Chainstack
  expected_chain=arbitrum
  error="invalid chain ID"

[INFO] 自动切换到下一个节点 node_id=6 provider=Alchemy
[INFO] RPC请求成功 method=eth_sendRawTransaction

**查询问题节点**:

1
2
3
4
5
6
7
8
9
-- 查看链ID不匹配的节点
SELECT id, provider, chain_id, http_url,
       chain_id_mismatch_count, last_error_message
FROM rpc_nodes
WHERE chain_id_mismatch_count > 0;

-- 输出:
-- id | provider   | chain_id | mismatch_count | last_error
-- 5  | Chainstack | arbitrum | 3              | invalid chain ID

错误统计

1
2
3
4
5
-- 查看节点错误统计(最近1小时)
SELECT * FROM node_error_stats;

-- 手动禁用问题节点(链ID不匹配 >= 5次)
SELECT * FROM auto_disable_problematic_nodes();

工作原理

系统不仅检查HTTP状态码,更重要的是**检查RPC响应体中的error字段**:

1
2
3
HTTP 200 OK ✅ → 继续检查
响应体: {"jsonrpc":"2.0", "error": {"code": -32000, "message": "invalid chain ID"}}
        ↑ 发现错误!识别类型 → 自动切换节点 → 重试成功

错误分类逻辑

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 1. 基于RPC错误码
if rpcError.Code == -32000 {
    if contains(message, "invalid chain id") {
        return CategoryChainMismatch  // 致命,自动切换
    }
}

// 2. 基于错误消息关键词
keywords := ["invalid chain id", "chain not supported", ...]
if containsAny(message, keywords) {
    return CategoryChainMismatch
}

管理操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
-- 查看问题节点
SELECT id, provider, chain_id, http_url,
       chain_id_mismatch_count, last_error_message, is_healthy
FROM rpc_nodes
WHERE chain_id_mismatch_count > 0
ORDER BY chain_id_mismatch_count DESC;

-- 查看错误统计(最近1小时)
SELECT * FROM node_error_stats;

-- 手动禁用问题节点
SELECT * FROM auto_disable_problematic_nodes();

-- 重置节点错误计数(问题修复后)
UPDATE rpc_nodes
SET chain_id_mismatch_count = 0,
    failure_count = 0,
    last_error_message = NULL,
    is_healthy = true
WHERE id = 5;

最佳实践

  1. **配置多个节点**:每条链至少2-3个不同提供商的节点
  2. **定期检查错误统计**:使用 node_error_stats 视图监控
  3. **及时修复问题节点**:收到链ID不匹配告警后立即检查配置
  4. **监控日志**:关注 chain_mismatchauth 类错误
1
2
# 实时监控链ID不匹配错误
tail -f log/crpc.log | grep -i "chain.*mismatch\|invalid.*chain"

许可证

MIT License

贡献

欢迎提交 Issue 和 Pull Request!

项目地址:https://github.com/your-org/crpc

联系方式