面试常问:既然有HTTP协议,为什么还要RPC协议和WebSocket协议?三者有什么区别?

0 阅读8分钟

HTTP 和 RPC 并非“二选一”的竞争关系,而是不同抽象层次的概念。理解这一点,是掌握现代后端架构设计的重要一步。


一、概念澄清:它们不在同一维度

维度HTTPRPC
定位传输协议(应用层协议,定义如何传输数据)通信范式(应用层协议,远程过程调用,定义如何组织调用逻辑)
类比像“快递公司”(负责把包裹从A送到B)像“点餐系统”(你点菜 → 厨房做 → 送回给你,你无需关心怎么做)
关系可作为 RPC 的传输载体(如 gRPC 基于 HTTP/2,JSON-RPC 基于 HTTP/1.1)可基于 HTTP、TCP、UDP 等多种协议实现

核心结论

  • 不存在“有了 HTTP 就不需要 RPC”的逻辑。
  • 正确说法是:在内部服务通信场景中,为何不直接用 HTTP/REST,而要引入 RPC 框架?

二、为何内部服务通信倾向用 RPC?五大核心动机

虽然 HTTP/REST 简单通用,但在高性能、强类型、大规模微服务场景下,传统 REST 存在明显短板。RPC 框架正是为解决这些问题而生:

1️⃣ 开发体验:像调本地函数一样调远程服务

// REST 风格(手动拼 URL、解析 JSON)
HttpResponse resp = httpClient.get("/users/123?fields=name,email");
User user = JSON.parse(resp.body(), User.class);

// RPC 风格(自动生成客户端 stub)
User user = userService.getUser(123); // ← 看起来就是本地方法调用!

转存失败,建议直接上传图片文件

  • IDL(接口定义语言)驱动:用 .proto(Protobuf)、.thrift 等定义接口,自动生成客户端/服务端代码。
  • 编译期类型检查:参数/返回值类型错误在编译时报出,而非运行时 JSON 反序列化失败。

2️⃣ 性能与效率:二进制协议 + 多路复用

特性HTTP/1.1 + JSONgRPC (HTTP/2 + Protobuf)Thrift (自定义二进制)
序列化文本(冗长,需解析)二进制(体积小 3~5 倍)二进制(高效)
多路复用❌ 队头阻塞✅ 单连接并发多请求
连接复用有限(Keep-Alive)原生支持原生支持
典型场景浏览器 → 后端微服务间通信高性能内部服务

💡 实测数据:Protobuf 序列化比 JSON 快 310 倍,体积小 35 倍(尤其对数字/布尔值优势明显)。 > > HTTP连接需要依靠Keep-ALive保持这个连接,而RPC底层有一个连接池,在请求量大的时候,会建立多条连接放在池子里,需要用的时候直接取出,用完放回去,方便下次复用

3️⃣ 服务发现

  • HTTP:通过DNS服务器去解析域名背后的IP地址,再注册服务
  • RPC:通过自行配置中间服务(如Redis)去获取IP地址和端口信息

4️⃣ 协议演进友好:向后兼容的版本管理

  • Protobuf/Thrift 支持字段增删(旧客户端忽略新字段,新客户端兼容旧数据)。
  • REST 的 JSON 结构变更易导致客户端解析失败,需谨慎设计版本(如 /v1/users/v2/users)。

5️⃣ 流式通信支持

  • gRPC 原生支持

    • 服务端流(Server Streaming):如实时推送日志
    • 客户端流(Client Streaming):如上传大文件分片
    • 双向流(Bidirectional Streaming):如聊天、IoT 设备通信
  • HTTP/1.1 实现流需用 Chunked Encoding,复杂且浏览器兼容差;HTTP/2 支持但生态工具少。


三、HTTP/REST 依然不可替代:适用场景对比

场景推荐方案原因
浏览器 ↔ 后端HTTP/REST + JSON浏览器原生支持,无需额外库
对外开放 APIHTTP/REST + OpenAPI易调试(curl/postman)、易文档化、易被 CDN/网关代理
异构系统集成HTTP/REST语言/平台无关性最强
内部微服务通信RPC(gRPC/Dubbo)性能、类型安全、服务治理优势明显
需要缓存/CDNHTTP/REST利用 Cache-ControlETag 等标准头
需要 SEO/可链接性HTTP/RESTURL 可被搜索引擎索引、可直接分享

现代架构趋势:混合使用

  • 对外:RESTful API(供 Web/App 调用)
  • 对内:gRPC(服务间高性能通信)
  • 网关层:将 REST 转为 gRPC(如 Envoy、Kratos 网关)

四、常见误区澄清

误区正解
“RPC 比 HTTP 快”不准确。gRPC 快是因为 HTTP/2 + Protobuf,而非“RPC”本身。用 HTTP/2 + Protobuf 实现 REST 同样高效。
“RPC 不安全”安全性取决于传输层(TLS)和认证机制,与是否 RPC 无关。gRPC 原生支持 TLS。
“REST 就是 HTTP”REST 是架构风格(基于资源、无状态、统一接口),HTTP 是实现它的常用协议。
“RPC 不能跨语言”主流 RPC 框架(gRPC/Thrift)均支持多语言代码生成。

总结:一张图看懂关系

┌─────────────────────────────────────────────┐
│          应用层通信需求                      │
└──────────────┬──────────────────────────────┘
               │
       ┌───────┴────────┐
       │                │
   ┌───▼─────┐      ┌───▼─────┐
   │  REST   │      │   RPC   │  ← 通信范式(如何组织调用)
   │ (资源)  │      │ (函数)  │
   └───┬─────┘      └───┬─────┘
       │                │
       └───────┬────────┘
               │
       ┌───────▼────────┐
       │   传输协议层    │
       ├────────────────┤
       │  HTTP/1.1      │
       │  HTTP/2 (gRPC) │ ← RPC 可基于 HTTP/2
       │  TCP (Thrift)  │
       └────────────────┘

💡 记住一句话
HTTP 是“路”,RPC 是“车”。你可以用 HTTP 这条路跑 REST 这辆车,也可以跑 gRPC 这辆车。选车的标准是:目的地(场景)和载重需求(性能/类型安全)。

扩展:那WebSocket协议呢?

概念澄清:它们解决的是不同问题

维度HTTPWebSocket
通信模式请求-响应(Request-Response) 客户端发起 → 服务器响应 → 连接关闭全双工双向通信(Full-duplex) 建立连接后,客户端和服务器可随时主动发送消息
连接生命周期短连接(HTTP/1.1 Keep-Alive 可复用,但仍是请求驱动)长连接(一次握手,持续通信,直到主动关闭)
类比对讲机:你说一句 → 对方回一句 → 等待下一轮电话通话:建立连接后,双方可随时插话、实时交流
协议标识http://https://ws://wss://(wss = WebSocket Secure)

核心结论
WebSocket 不是 HTTP 的替代品,而是为了解决 实时双向通信 场景而诞生的补充协议。


二、HTTP 的局限性:为什么它不适合实时场景?

问题 1:请求必须由客户端发起

客户端:我能问问题吗? → 服务器:可以
客户端:现在有新消息吗? → 服务器:没有
客户端:现在有新消息吗? → 服务器:没有
客户端:现在有新消息吗? → 服务器:有!"Hello"
  • 服务器有新数据时,无法主动推送给客户端
  • 客户端只能不断“轮询”(Polling),浪费资源

问题 2:轮询方案的缺陷

方案描述缺点
短轮询(Short Polling)客户端定时发起 HTTP 请求大量无效请求,延迟高(取决于轮询间隔)
长轮询(Long Polling)客户端发起请求,服务器挂起直到有数据仍基于请求-响应,连接频繁建立/断开,服务器压力大
SSE(Server-Sent Events)服务器可单向推送(基于 HTTP)仅支持服务器 → 客户端,客户端无法主动发消息

📊 数据对比(假设每秒检查一次新消息):

  • 短轮询:每分钟 60 次 HTTP 请求(大部分是空响应)
  • WebSocket:1 次握手 + 仅在有数据时传输 → 节省 90%+ 带宽

三、WebSocket 的核心优势

1️⃣ 真正的双向实时通信

握手阶段(基于 HTTP):
  客户端:GET /chat HTTP/1.1 + Upgrade: websocket
  服务器:101 Switching Protocols(协议升级)

通信阶段(切换到 WebSocket 协议):
  服务器:{"type": "message", "text": "有人加入了房间"}
  客户端:{"type": "message", "text": "Hello everyone!"}
  服务器:{"type": "typing", "user": "张三"}  ← 服务器主动推送
  客户端:{"type": "reaction", "emoji": "👍"}
  • 任意一方可随时发送消息,无需等待对方请求
  • 消息延迟 ≈ 网络传输时间(毫秒级)

2️⃣ 协议开销极小

协议消息头开销说明
HTTP~200-800 字节每次请求都带完整 Header(User-Agent、Cookie 等)
WebSocket2-14 字节帧头极简,适合高频小消息

💡 举例:发送 10 字节消息

  • HTTP:10 + 500(Header)= 510 字节
  • WebSocket:10 + 2(帧头)= 12 字节 → 节省 97% 带宽

3️⃣ 连接复用,资源消耗低

  • 一次握手建立连接,长期保持(心跳保活)
  • 无需频繁建立 TCP 连接(3 次握手 + TLS 握手)
  • 适合海量并发连接场景(如聊天室、在线游戏)

四、WebSocket 与 HTTP 的关系:握手阶段

WebSocket 握手阶段基于 HTTP,之后升级为独立协议:

// 客户端发起握手(HTTP GET)
GET /ws HTTP/1.1
Host: example.com
Upgrade: websocket          ← 告诉服务器:我想升级协议
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

// 服务器响应(101 状态码:协议切换)
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

🔑 关键点

  • 使用 Upgrade: websocket 头告知服务器意图
  • 服务器返回 101 Switching Protocols 状态码
  • 之后通信不再使用 HTTP 协议,而是 WebSocket 帧协议

五、典型应用场景对比

场景推荐协议原因
网页聊天 / 即时通讯WebSocket消息需实时双向推送,延迟要求低
在线游戏(如 MMO)WebSocket高频状态同步(玩家位置、技能释放)
股票/行情推送WebSocket / SSE服务器持续推送价格变动
协同编辑(如在线文档)WebSocket多人实时同步光标、内容变更
直播弹幕 / 互动WebSocket用户发送弹幕 + 服务器广播给所有人
IoT 设备监控WebSocket / MQTT设备状态实时上报 + 远程控制指令下发
普通网页浏览HTTP请求-响应模型完全够用
RESTful APIHTTP资源操作(CRUD),无需长连接
文件上传/下载HTTP大文件传输,HTTP 工具链成熟