跳至内容
0%

Webhooks、WebSockets 与 gRPC 对比

发布于 2026年5月19日4 分钟阅读

对比 webhooks、WebSockets 和 gRPC 实时数据传输方式的封面图

每个读取区块链数据的应用都面临同一个架构问题:数据应该如何到达你的系统?每隔几秒轮询一次 API,会浪费计算资源、错过事件,还会增加延迟。改为推送数据,你就需要选择一种投递模型。

三种协议主导着实时数据投递:webhooksWebSockets 和 gRPC。它们并不可以互相替代。Webhooks 在某件事发生时通知你的后端。WebSockets 向浏览器流式传输实时数据。gRPC 以高吞吐量在后端服务之间传输数据。选错了协议,代价会在之后才显现:错过的事件、浪费的计算资源,或是一次你没有计划过的系统重构。

Webhooks、WebSockets 和 gRPC 分别是什么?

三者都可以在不轮询的情况下将数据从服务器传送到你的应用,但相似之处也就到此为止。

webhook 颠倒了常见的 API 方向。不是你的代码调用服务器,而是服务器在它关心的事情发生时,携带 JSON 负载调用你注册的 URL。Webhooks 接入很简单,代价是你无法控制到达数据的时机和形状。

WebSocket 是客户端与服务器之间的一条持久 TCP 连接。任意一方都可以随时发送小的二进制帧,而无需重新建立连接。该协议以一个 HTTP 请求开始,一旦双方同意升级,便切换为一条原始套接字连接。

gRPC 是一个远程过程调用(RPC)框架:它让一个服务可以像调用本地函数一样调用另一个服务中的函数。作为 Google 内部 RPC 系统 Stubby 的公开继任者,gRPC 运行在 HTTP/2 之上,使用 Protocol Buffers 序列化数据,并支持包括全双工在内的四种流式模式。它是为在机器之间快速传输结构化数据的后端服务而构建的,内置重试、超时期限传播和类型化契约。

Dimension
Webhooks
WebSockets
gRPC
协议
HTTP POST 回调
持久 TCP(RFC 6455
方向
服务器到接收方(单向)
双向
双向(4 种流式模式)
连接模型
无状态(每个事件新建请求)
有状态(持久连接)
有状态(持久、多路复用)
数据格式
JSON
JSON 或二进制
Protobuf(二进制)
单条消息开销
500-2,000 字节(HTTP 头)
2-6 字节
5 字节帧 + 压缩后的头部
浏览器支持
不适用(服务器端)
原生支持(99%+)
需要 gRPC-Web 代理
投递保证
至少一次(带重试)
无内置保证
可配置的重试 + 超时期限
最适用场景
事件通知
实时浏览器界面
服务间数据管道

Webhooks 是如何工作的?

Webhooks 颠倒了 API 模型。不是你调用服务器,而是服务器调用你。你向某个提供方注册一个 URL,告诉它哪些事件是你关心的,然后等待。一旦事情发生,提供方就会向你的端点 POST 一段 JSON,并期望收到一个 2xx 响应。

javascript
Copied
app.post('/webhook', (req, res) => { const sig = req.headers['x-alchemy-signature']; if (!verify(sig, req.rawBody, SECRET)) return res.status(401).end(); queue.enqueue(req.body); res.status(200).end(); });

上面的代码片段是一个 webhook 处理器:它验证签名、将负载入队,然后返回 200。而上面这个简单版本,恰恰也是生产环境中大多数 webhook 故障的来源。区分一个玩具级处理器和生产级处理器的,是它如何处理简单版本处理不当的三件事:签名验证、重试行为,以及突发过载。

第一种故障模式是薄弱的签名处理。提供方会用一个共享密钥对每次投递做 HMAC 签名(Alchemy 使用 X-Alchemy-Signature,Stripe 使用 Stripe-Signature),你的处理器必须重新计算 HMAC,用恒定时间比较以避免时序攻击,并拒绝任何时间戳早于五分钟前的请求。调用 verify() 只是一行代码,但正确地完成它需要好几步。跳过任何一步,你就相当于信任了任何知道你端点 URL 的进程。

第二种故障模式是在重试下的非幂等处理。当投递失败时(超时、部分中断、5xx 响应),提供方会以指数退避方式重试(通常从一秒开始翻倍,加入抖动,上限为一小时),持续数小时甚至数天,之后才将负载发送到死信队列。Webhooks 保证的是至少一次投递,而不是恰好一次(恰好一次在分布式系统中是不可能实现的),因此重复投递是常态。你的处理器必须是幂等的:处理同一事件两次应该产生与处理一次相同的结果。在去重存储中跟踪事件 ID,对重复请求返回 200。

第三种故障模式是突发过载,这也是在规模化时导致 webhook 系统崩溃的那一种。单个链上事件可能触发数百万次并发投递。如果你的端点成为瓶颈,提供方的重试队列就会变成攻击你的 DoS 工具。

在区块链基础设施中,webhooks 支撑着事件驱动的工作流。我们的 Custom Webhooks 支持地址活动监控、NFT 转账提醒,以及跨 30 多条 EVM 链和 Solana 的 GraphQL 过滤智能合约事件,全部以 HTTP POST 回调的形式投递到你的端点。

WebSockets 是如何工作的?

一个 WebSocket 连接以一个带有 Upgrade: websocket 头部的普通 HTTP 请求开始。服务器回复 HTTP 101(Switching Protocols),从这一刻起,连接不再使用 HTTP 通信。这次协商就是所谓的 WebSocket 握手。之后剩下的是一条原始 TCP 套接字,上面叠加了一层薄薄的分帧机制:每条消息没有头部,也没有请求-响应循环。

去掉 HTTP 使得 WebSockets 在单条消息上的开销大幅降低。每条 WebSocket 消息只带有 2-6 字节的开销(一个 FIN 位、操作码,以及负载长度)。相比之下,HTTP 的每个请求都包含数百字节的头部。在每秒 100 条消息的情况下,WebSocket 的开销大约是每秒 600 字节,而等量的 HTTP 流量则约为每秒 60,000 字节。

javascript
Copied
const ws = new WebSocket('wss://eth-mainnet.g.alchemy.com/v2/KEY'); ws.send(JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'eth_subscribe', params: ['newHeads'] })); ws.on('message', (data) => handleBlock(JSON.parse(data)));

WebSocket 连接是有状态且长期存在的。任意一方都可以随时发送数据,而无需等待对方。服务器会定期发送 ping 帧,客户端以 pong 帧回应,以证明连接仍然存活。没有这些心跳,死连接(“僵尸连接”)会持续占用服务器资源,而反向代理通常会在 30-120 秒的空闲后终止连接。

代价是:连接的生命周期由你自己负责,而这个生命周期中的细节比乍看之下要多。当连接断开时,你的客户端必须重新连接,而且要以指数退避方式重连(重试间隔逐渐拉长),否则成千上万个客户端同时重连会压垮服务器。当你在负载均衡器后面运行多个 WebSocket 服务器时,负载均衡器必须把来自某个客户端的每次重连都路由回同一台机器,因为那台机器保存着该客户端的订阅状态。这条路由规则有一个专门的名字:会话保持(session affinity)。而如果一条消息产生于某台服务器,却需要送达连接在另一台服务器上的客户端,那么这些服务器之间就必须在节点间共享状态。WebSockets 给你的是这条线路协议;协议之上的一切都要你自己搭建。

对于区块链应用来说,WebSockets 是实时事件订阅的标准接口。Ethereum 的 eth_subscribe 端点 通过一条持久的 WebSocket 连接推送新区块头、日志事件和待处理交易。我们的 Smart WebSockets 在基础协议之上增加了过滤订阅和自动重连功能。

向浏览器流式传输实时数据正是 WebSockets 被设计来解决的问题。在 WebSockets 出现之前,可选方案(长轮询、服务器发送事件)要么每条消息都要承担完整的 HTTP 开销,要么只能单向工作。WebSockets 在浏览器这个原始 TCP 套接字通常无法生存的场景中,提供了一条持久、低开销、双向的连接。

这种清晰性同时也是它的局限。当消费者不是浏览器、数据是结构化的、量很大,并且你需要一些 WebSockets 从未承诺过的东西(类型化模式、多路复用流、超时期限传播、背压)时,WebSockets 就会遇到困难。而这正是 gRPC 被设计来解决的问题。

gRPC 是如何工作的?

gRPC 从设计空间的另一端出发。Webhooks 是 HTTP 回调,WebSockets 是 TCP 之上的一层薄分帧,而 gRPC 是一个以类型化契约为核心的完整 RPC 框架。在编写任何业务逻辑之前,你要先编写一个 .proto 文件,定义你的服务以及它收发的消息。protobuf 编译器会把这个文件转换成你所用语言的客户端和服务端生成代码(称为 stub),这样在你的代码中调用远程方法就像调用本地函数一样。

protobuf
Copied
service Geyser { rpc Subscribe(stream SubscribeRequest) returns (stream SubscribeUpdate); }

传输层是 HTTP/2,配合 Protocol Buffers 做序列化。两者结合,使 gRPC 相比典型的 REST + HTTP/1.1 + JSON 技术栈拥有三项优势:

  • 多路复用消除了队头阻塞(head-of-line blocking)——这是 HTTP/1.1 的一个问题,即单个缓慢的响应会阻塞同一连接上后续的所有请求。在 gRPC 中,每次调用作为一个独立的 HTTP/2 流运行,共享同一条 TCP 连接。Square 就是将内部服务间流量迁移到 gRPC 以降低连接开销的众多工程团队之一。
  • 头部压缩(HPACK)用紧凑的引用替代重复的头部。在 RPC 流量中,同样的方法、内容类型和鉴权头部会在每次调用中重复出现,这能将头部开销降低 85-90%
  • Protocol Buffers 将消息序列化为紧凑的二进制格式,而不是文本。在未压缩的环境中,负载体积比 JSON 小 34%,反序列化速度最高快 6 倍,具体取决于所用语言。代价是:二进制负载不可读,你需要 grpcurl 或 Postman 之类的工具来检查流量。

gRPC 支持四种流式模式。一元模式(一次请求,一次响应)的工作方式类似标准 API 调用。服务器流模式(一次请求,多次响应)适合 feed 和数据推送。客户端流模式(多次请求,一次响应)用于处理批量上传。双向流模式(双方都可独立发送)支撑实时、有状态的交互。

gRPC 并不是一个通用协议。它专门针对在你控制两端的机器之间以高速率传输结构化数据的后端服务做了优化,而这个聚焦的细分场景,恰恰是编写模式和运行代码生成所付出的前期成本能够收回的地方。让 gRPC 处于这个位置的,不只是二进制编码,还有内置在协议中的生产级原语。超时期限传播把每个超时都变成一个贯穿整条调用链的绝对时间点。如果服务 A 设置了 5 秒的期限并调用服务 B,服务 B 再调用服务 C,那么每一跳都清楚地知道还剩多少时间。期限到期时,所有下游工作都会取消并释放资源。流量控制继承自 HTTP/2:当消费方处理不过来时,发送方会自动放慢速度以匹配。这是内置的背压机制,而 webhooks 和 WebSockets 都没有原生提供。

Solana 上,gRPC 支撑着目前性能最高的数据流式传输方案。Yellowstone gRPC 插件(Geyser)直接加载到验证者节点的内存空间中,在账户和交易更新落盘之前就将其捕获,序列化为 protobuf,并通过持久的 HTTP/2 流推送出去。

三种协议在性能上如何比较?

吞吐量和延迟基准测试为服务间通信划出了一条清晰的界线。二进制 protobuf 编码加上 HTTP/2 多路复用,使 gRPC 在吞吐量和延迟上明显优于基于 HTTP/1.1 的 REST,尤其是在负载小、并发调用多的工作负载中。

WebSockets 在另一个维度上胜出:浏览器到服务器流式传输中最低的单条消息开销。在初始握手之后,每条消息只携带 2-6 字节的分帧开销,浏览器原生的 WebSocket API 无需代理或构建工具即可处理连接。

Webhooks 的设计目标并不是性能。每次投递都是一个独立的 HTTP 请求,带有完整的连接建立开销。它们解决的是另一个问题:可靠的、异步的事件通知,在这种场景中,简单性和兼容性比吞吐量更重要。

Metric
Webhooks
WebSockets
gRPC
单条消息延迟
最高(完整 HTTP 往返)
低(2-6 字节帧)
最低(二进制 + 多路复用)
吞吐量上限
受限于 HTTP 开销
单条流下较高
最高(多路复用流)
序列化成本
仅 JSON
JSON 或二进制
连接建立
每个事件一次(或复用连接)
一次,之后保持持久
一次,之后保持持久 + 多路复用
背压
无(接收方自行承受或失败)
无内置机制
内置(HTTP/2 流量控制)

针对区块链的具体数据也印证了这一规律。Solana 的 Yellowstone gRPC 以约 5ms 的槽位延迟流式传输数据;原生 WebSockets 的投递延迟约为 10ms;RPC 轮询则滞后约 150ms。协议复杂度每提升一级,都能换来可衡量的速度提升。

每种协议在什么情况下会失效?

Webhooks 在高频事件下表现吃力。在每秒数百次投递的情况下,每次回调的 HTTP 开销会成为瓶颈。突发事件会造成惊群问题:一个重大链上事件会同时触发数百万次 webhook 投递,让提供方的重试队列和消费方的端点都不堪重负。Webhooks 还严格是单向的。任何需要双向通信的场景都需要另一种协议。正如一位构建过 webhook 基础设施的工程师所说:“webhooks 运行起来很痛苦。”

WebSockets 在规模化时会遇到困难。每条连接都会占用服务器资源(空闲时 2-10 KB,活跃时更多)。经过调优的服务器可以处理超过 50 万条空闲连接,但真正的瓶颈是连接的高流失率:每个 CPU 核心每秒能处理的 TLS 握手数量约为 1,000-3,000 次。当服务器重启时,所有已连接的客户端会同时重连,形成重连风暴,可能演变为一次完全的服务中断。在 Solana 上,标准的 WebSocket 实现“在负载下变得不可靠”,性能下降且频繁断连,这促使 Solana 团队转向 gRPC。

gRPC 在浏览器端会遇到困难。浏览器无法原生使用 gRPC。gRPC-Web 协议通过代理(通常是 Envoy)弥合了这一差距,但过程中会失去客户端流和双向流能力。二进制 protobuf 负载无法用 curl 或浏览器开发者工具直接查看,这使得 gRPC 不太适合开发者体验很重要的公开 API。protobuf 工具链(模式定义、代码生成、构建集成)也为简单的集成带来了不小的前期成本。

应该如何在 webhooks、WebSockets 和 gRPC 之间做选择?

先从你的用例所需要的通信模式出发。

Webhooks 是默认选项。如果你的后端需要在某个离散事件发生时(交易确认、NFT 转账、支付完成)得到通知,且事件速率保持在每秒几百次以内,那么 webhooks 是成本最低的集成方式,可以在任何语言、任何框架、任何防火墙环境下工作。不需要持久连接,不需要流式基础设施,也不需要客户端 SDK。

当事件速率上升,或者你需要数据双向流动时,就轮到 WebSockets 出场了。想想实时价格行情、订单簿更新、内存池监控、协作式仪表盘:任何一种通过对浏览器保持持久连接来避免频繁调用 API 的场景都适用。原生浏览器支持,无需代理,帧开销以字节计。

当你需要在后端服务之间实现最大吞吐量时,选择 gRPC。索引器数据管道、验证者数据流、微服务间通信,以及任何你能同时控制连接两端的工作负载,都能从二进制序列化、多路复用流、类型化契约和内置背压中受益。代价在于工具链:protobuf 模式、代码生成、没有原生浏览器支持。当性能和可靠性的收益超过搭建成本时,这些代价是值得的。

在架构需要时,可以把三者结合起来使用。许多生产系统会同时使用这三种协议:用 gRPC 把数据从验证者流式传输到索引器,用 WebSockets 把处理后的数据推送到浏览器仪表盘,用 webhooks 通知外部系统离散事件的发生。没有理由把所有身家都押在单一协议上。

Use case
Recommended protocol
Why
交易确认提醒
Webhooks
离散事件、简单集成、至少一次投递
交易界面中的实时价格行情
WebSockets
向浏览器连续传输数据、低延迟、双向
Solana 验证者数据管道
gRPC
最大吞吐量、二进制序列化、背压
Ethereum 新区块订阅
WebSockets
标准 eth_subscribe 接口,兼容浏览器
后端微服务间通信
gRPC
类型化契约、多路复用、超时期限传播
第三方集成回调
Webhooks
通用 HTTP 兼容性,无需持久连接

在 Alchemy 上构建基于实时区块链数据的应用

我们在100 多条链上支持这三种协议。

我们的 Custom Webhooks 以 HTTP POST 回调的形式投递交易确认、地址活动和 NFT 事件,并提供 HMAC 签名验证和自动重试。GraphQL 过滤器让你可以精确订阅应用所需的合约事件。

Smart WebSockets 提供经过过滤的 eth_subscribe 流,具备自动重连功能,为实时前端应用降低延迟。

对于处理高流量数据的 Solana 团队,我们的 Yellowstone gRPC streaming 直接从验证者内存中投递账户更新和交易,延迟低于 10ms。

三种能力在我们的免费套餐中均可使用。无需签约,无需排队等待。注册后即可在几分钟内开始流式传输数据。

常见问题

Webhooks、WebSockets 和 gRPC 之间的主要区别是什么?

Webhooks 是用于服务器间事件通知的单向 HTTP 回调;WebSockets 提供客户端与服务器之间持久的双向连接;gRPC 是运行在 HTTP/2 之上的 RPC 框架,专为需要类型化契约的高吞吐量服务间通信而设计。

什么时候应该使用 webhooks 而不是 WebSockets 或 gRPC?

当你需要接收离散事件通知(比如交易确认或 NFT 转账),且事件速率在每秒几百次以内,同时不需要持久连接时,使用 webhooks。它们是最简单的集成方式,不需要专门的客户端 SDK 或基础设施。

什么时候 WebSockets 是更好的选择?

WebSockets 最适合向浏览器客户端连续传输实时数据,比如实时价格行情、订单簿更新或仪表盘。它们提供原生浏览器支持,握手完成后单条消息开销很低(2-6 字节)。

gRPC 是为了解决什么问题而设计的?

gRPC 针对以高速率传输结构化数据的后端服务做了优化,比如索引器数据管道或验证者数据流。它通过 Protocol Buffers 提供二进制序列化、多路复用流、类型化契约、内置背压和超时期限传播。

我可以在同一个系统中同时使用 webhooks、WebSockets 和 gRPC 吗?

可以,许多生产系统会同时结合使用这三种协议:用 gRPC 处理后端服务间通信,用 WebSockets 向浏览器推送实时更新,用 webhooks 通知外部系统离散事件的发生。每种协议解决的是架构中不同的层面。

这些协议之间的性能差异是什么?

gRPC 通过二进制编码和 HTTP/2 多路复用实现最低的延迟和最高的吞吐量;WebSockets 在浏览器流式传输中开销很低(每条消息 2-6 字节);webhooks 由于完整的 HTTP 往返开销,单条消息成本最高,但它优先考虑的是简单性而非性能。

每种协议的主要缺点是什么?

Webhooks 在高频事件和突发流量下表现吃力;WebSockets 在规模化时面临连接高流失率和惊群式重连风暴带来的挑战;gRPC 需要搭建 protobuf 工具链,缺乏原生浏览器支持,且需要代理(gRPC-Web)才能服务于 Web 客户端。

Alchemy 如何为区块链应用支持这些协议?

Alchemy 提供 Custom Webhooks,用于在 100 多条链上进行事件通知;提供 Smart WebSockets,用于带自动重连的过滤 eth_subscribe 流;并在 Solana 上提供 Yellowstone gRPC streaming,直接从验证者内存中投递账户更新,延迟低于 10ms。

Background gradient

构建区块链应用

Alchemy 将最强大的 Web3 开发者产品和工具与资源、社区及专业支持结合在一起。