前一章我讲的是 Besu 的组件结构,这一章我把它落到实际操作上:我怎么连它、怎么查它、怎么订阅事件、怎么判断它是不是被安全地暴露出去,以及我出问题时先看什么。
一、为什么不能把 Besu 当成"一个 JSON-RPC 服务器"?
很多人第一次接触 Besu,都会把它简化成"一个能跑 eth_blockNumber 的节点",对此我有不同的理解。Besu 的 API 不是单一路径,而是至少分成三种很不一样的使用方式:JSON-RPC 适合请求<->响应,RPC Pub/Sub 适合订阅事件,而 GraphQL 则适合高效查询结构化数据。
这对于开发者就非常友好。
试想一下,把所有事情都塞进 JSON-RPC,不仅写起来笨,在调试和监控上也非常影响性能。比如我想持续盯着某些事件出现,用轮询查 eth_getLogs 就会占用很多不必要的带宽。如果我只想一次拿到一个 block 的很多信息,GraphQL 往往比 RPC 更省事。因为 GraphQL 可以把"查一个区块里的 receipts"这类常见操作压缩成一个查询非常方便。
二、JSON-RPC 的三个入口
Besu 的 JSON-RPC 可以通过 HTTP、WebSocket 和 IPC 三种方式使用。
- 启用 HTTP 要用
--rpc-http-enabled; - 启用 WebSocket 要用
--rpc-ws-enabled; - 启用 IPC 要用
--Xrpc-ipc-enabled;
注意,客户端不是默认给你开好所有口子的,必须显式启用。
那么应该什么时候用什么方式呢?
HTTP 适合最普通的请求,WebSocket 适合长连接和订阅,而 IPC 适合本机上更轻量、更直接的进程间调用。尤其是订阅类方法,eth_subscribe 和 eth_unsubscribe 可以走 WebSocket 或 IPC,但不能走 HTTP。这个限制非常重要,因为很多人第一次做事件监听时,明明把接口开了,却总觉得"怎么订阅不生效",原因通常就是通道选错了。
三、 关于 RPC Pub/Sub 是事件系统的这件事儿
RPC Pub/Sub 的核心不是"发一个请求拿一个结果",而是"先订阅,再等节点主动推送"。Besu 官方文档说明,eth_subscribe 会返回一个 subscription ID,之后所有通知都会带着这个 ID。而且订阅是和连接绑定的,连接断了,订阅也会跟着失效。
我特别喜欢这个设计,因为它非常适合企业链里的"持续观察"。譬如我想监听某个合约事件,WebSocket 订阅要比不停轮询省得多。如果我想知道节点是不是正在同步,syncing 订阅也能直接告诉我状态变化。此外,如果节点正在同步,某些订阅会短时间内涌入大量通知,所以监听端也要做好限流和缓冲,不然调试工具自己先被刷爆(经验之谈)。
四、被大家低估的 GraphQL
GraphQL 在 Besu 里其实非常实用。它能够有效减少常见查询的开销,比如查询 block 里的 receipts,不需要拆成多次的 RPC 请求,唯一的遗憾就是它不支持 WebSocket。
我对 GraphQL 的理解是:它特别适合"我要一次把结构化数据拿完整"的场景。比如我想把区块相关信息一起取回来,GraphQL 能减少我在客户端做拼装的工作。这个思路在调试报表、审计页面和内部运维看板里尤其好用,因为它天然更接近"我要什么字段,就拿什么字段"的思维,而不是"先调一堆接口再自己拼"。
五、allowlist 不是权限控制
这是我最想强调的一点。
Besu 会检查 HTTP 请求的 host header、WebSocket 连接和 GraphQL 请求,以防 DNS rebinding 攻击。匹配规则由 --host-allowlist 控制,默认只接受 localhost 和 127.0.0.1。但 host allowlist 不是 permissioning 功能。如果真要限制 API 访问,应该用 Besu 的认证机制,比如用户名密码认证或 JWT 公钥认证。这很关键,因为它直接决定我怎么部署。也就是说,就算我把 allowlist 配对了,也不代表外部客户端就"合法"了。它只是告诉 Besu 这些 host 允许被接收。真正的访问控制还得靠认证。
六、排障先看日志级别和请求入口
Besu 的日志控制很直接:--logging 可以设为 OFF、ERROR、WARN、INFO、DEBUG、TRACE、ALL,默认是 INFO。Besu 其实有提供运行时动态改日志级别的方法 admin_changeLogLevel,这能让我在不重启节点的情况下,把调试信息临时打深。
我的经验是,真正难查的问题,往往不是"没日志",而是"日志太少"。所以我通常先从入口层判断:
HTTP 请求有没有进来,WebSocket 有没有建立,GraphQL 有没有被允许,RPC 是否启用。然后再把日志级别往上提,等我看到足够的信息后再降回去。
七、将 metrics 当成"第二眼睛"
metrics 对于我来说属于排障基本盘。在实际生产中我会选用 Prometheus 访问 Besu 指标,这个只需要在配置中将 --metrics-enabled 启用即可,然后用 Grafana 可视化。Prometheus 可用来监控节点距离 chain head 落后了多少区块。这个指标是非常实用的,因为它能直接告诉我节点是不是跟链头脱节了。
此外,Besu 还支持 push 模式。
如果不好从外部拉指标,也可以启用 --metrics-push-enabled,把指标推到 Prometheus。在 Docker 或 IP 变化很频繁的环境里,push 模式会更实用一些。这意味着监控不必死守一种拓扑,尤其在容器化部署里非常方便。
除了 Prometheus 外 OpenTelemetry 将会是我第二选择。只要启用 --metrics-enabled 和 --metrics-protocol=opentelemetry,就可以收集节点 metrics 和 traces。它能帮我看 sync time,以及时间到底花在 Besu 内部还是 JSON-RPC 接口上。这个视角对定位"为什么接口慢"特别有帮助。
八、我的排障链路
今时今日如果我再遇到 Besu 节点异常,我的排查顺序应该会:
- 先确认 JSON-RPC、WS、GraphQL 哪个入口实际开着;
- 再看认证是否通过;
- 然后看日志级别是否足够;
- 再看 metrics 是否显示节点落后链头;
- 最后才去分析具体请求本身。
如果是订阅类问题,我会先确认连接是不是 WebSocket 或 IPC,因为 HTTP 本身就不支持 eth_subscribe。如果是查询类问题,我会想 GraphQL 能不能减少调用次数。如果是链头追不上,我就直接去看 metrics 里的 chain head lag。
九、写在最后
我一般会把 API 使用分成三类:
- 第一类是"查状态",比如版本、peer 数、区块高度;
- 第二类是"等事件",比如 logs、headers、pending tx;
- 第三类是"做结构化查询和运维动作",比如 GraphQL 查询、调日志、看指标。
Besu 的 Postman 文档也专门提供了 API 示例和多语言请求样例,所以在工程上我不需要一开始就手搓所有调用。此外,我还会按照状态去区分使用的接口类型的。就譬如,如果某个系统只是读取信息,尽量别把它和高权限 API 混在一起;如果某个系统要订阅事件,就专门给它 WebSocket 或 IPC,而不是把它硬塞进 HTTP;如果某个系统要做审计报表,就优先考虑 GraphQL 这类结构化查询。
通过这样拆分后,权限、性能和排障都会清楚很多。