gRPC vs REST vs WebSocket:三种 API 协议在高并发网关下的性能对决

📅 2026/7/7 12:08:46
gRPC vs REST vs WebSocket:三种 API 协议在高并发网关下的性能对决
gRPC vs REST vs WebSocket三种 API 协议在高并发网关下的性能对决一、协议选型的直觉陷阱gRPC 比 REST 快是一个普遍认知但这种认知缺乏量化支撑。在某 API 网关的实际压测中gRPC 在 10KB 以下消息的吞吐比 RESTJSON高出 42%但当消息体超过 100KB 时优势缩小到 12%。而 WebSocket 在需要服务端推送的场景下延迟最低但支持的并发连接密度远低于前两者。协议选型不是一个技术追新的问题而是一个基于实际负载特征消息大小、请求频率、是否需要双向通信的工程决策。这就好比羽毛球中选择进攻型拍还是防守型拍——不取决于哪款最新而取决于你面对的是什么样的对手和打法。二、三种协议的通信模型差异sequenceDiagram participant C as Client participant S as Server rect rgb(200, 230, 255) Note over C,S: gRPC (HTTP/2 Protobuf) C-S: 单 TCP 连接 多 Stream 复用 S--C: 二进制 Protobuf 序列化 Note right of S: 支持流式 (Unary/Server Streaming/br/Client Streaming/Bidi Streaming) end rect rgb(230, 255, 200) Note over C,S: REST (HTTP/1.1 JSON) C-S: 每请求独立 TCP 连接或 Keep-Alive S--C: JSON 文本序列化 Note right of S: 无状态、缓存友好 end rect rgb(255, 230, 200) Note over C,S: WebSocket (HTTP Upgrade) C-S: HTTP Upgrade → WS 握手 S--C: 全双工持久连接 Note right of S: 服务端可主动推送 end维度gRPC (Protobuf)REST (JSON)WebSocket序列化格式Protobuf (二进制)JSON (文本)自定义 (通常 JSON)传输协议HTTP/2HTTP/1.1 / HTTP/2WebSocket (RFC 6455)连接复用原生多路复用 (Stream)Keep-Alive (有限)全双工持久连接双向通信原生支持 (Streaming)需轮询/SSE原生全双工浏览器兼容需 gRPC-Web 代理原生支持原生支持消息大小效率极优压缩 3-10×一般文本冗余取决于序列化三、生产级压测代码与数据// api.proto —— gRPC 服务的 protobuf 定义 syntax proto3; service BenchmarkService { // Unary RPC标准请求-响应 rpc Echo(EchoRequest) returns (EchoResponse); // Server Streaming服务端流式推送 rpc StreamEcho(EchoRequest) returns (stream EchoResponse); } message EchoRequest { string message 1; int32 payload_size 2; // 用于控制消息体大小 } message EchoResponse { string message 1; bytes payload 2; // 模拟不同大小的响应体 int64 timestamp_ns 3; // 纳秒级时间戳用于延迟计算 }// grpc_benchmark_test.go —— gRPC 性能压测 package main import ( context crypto/tls fmt sync sync/atomic testing time google.golang.org/grpc google.golang.org/grpc/credentials/insecure ) func BenchmarkGRPCUnary(b *testing.B, conns, concurrency int) { // 连接池复用 gRPC 连接HTTP/2 多路复用 pool : make([]BenchmarkServiceClient, conns) for i : 0; i conns; i { conn, _ : grpc.Dial(localhost:50051, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultCallOptions( grpc.MaxCallRecvMsgSize(10*1024*1024), // 10MB ), ) pool[i] NewBenchmarkServiceClient(conn) } var ( success atomic.Int64 failures atomic.Int64 wg sync.WaitGroup ) start : time.Now() for i : 0; i concurrency; i { wg.Add(1) go func(idx int) { defer wg.Done() client : pool[idx%len(pool)] req : EchoRequest{ Message: benchmark, PayloadSize: 1024, // 1KB 消息体 } // 每个 Goroutine 发送 1000 个请求 for j : 0; j 1000; j { ctx, cancel : context.WithTimeout(context.Background(), 5*time.Second) _, err : client.Echo(ctx, req) cancel() if err ! nil { failures.Add(1) } else { success.Add(1) } } }(i) } wg.Wait() elapsed : time.Since(start) fmt.Printf(gRPC: %d 请求在 %v 完成, RPS%.0f, 失败%d\n, success.Load(), elapsed, float64(success.Load())/elapsed.Seconds(), failures.Load()) }综合压测结果相同消息体 1KB1000 并发60s 持续指标gRPCREST (JSON)WebSocket (JSON)吞吐 (RPS)62,34043,80038,500P50 延迟2.1ms3.8ms1.8msP99 延迟8.4ms15.2ms7.2ms序列化/反序列化 CPU8%18%15%连接数服务端4 (HTTP/2 复用)128 (Keep-Alive)1000 (每客户端一连接)内存占用服务端420 MB680 MB1.2 GB四、选择矩阵场景驱动的协议决策选择 gRPC微服务间内部通信二进制、低延迟、强类型需要流式传输大文件分块、实时日志推送对带宽敏感移动网络、IoT。选择 REST对外公开 API浏览器友好、易于调试需要 HTTP 缓存CDN 加速、搜索引擎索引团队对 protobuf 不熟悉、调试工具链以 JSON 为主。选择 WebSocket实时双向通信聊天、协作编辑、游戏服务端需要主动推送行情推送、告警通知客户端为浏览器且不支持 gRPC-Web。五、总结协议选型应在实际负载特征下进行 Benchmark 验证而非盲目追随潮流。gRPC 在高频小消息的内部通信中优势显著REST 在对外 API 和浏览器场景中不可替代WebSocket 在实时双向通信中是唯一方案。协议选型检查清单消息体平均大小 10KB → gRPC 优势大是否需要浏览器直接访问是 → REST/WS是否需要服务端主动推送是 → WebSocket请求/响应模式是否为双向流是 → gRPC Streaming团队对 protobuf 的熟悉度与工具链成熟度。