bigywater.tech
Redis · 104

RESP2 与 RESP3

RESP3 不是「更快的协议」,而是「有类型的协议」:客户端能直接知道一个回复是 map、集合还是浮点数,而不必靠命令名去猜。这篇用原始 socket 把同一条命令在 RESP2 与 RESP3 下的字节逐个摆出来,并看它新增的服务器推送。

HELLO 3
同一条连接上切到 RESP3;HELLO 2 可以切回
2586 = 2586 字节
100 个字段的 HGETALL 在两种协议下的大小——RESP3 改的是类型,不是体积
> 推送
CLIENT TRACKING 下,服务器主动发出的 invalidate 消息

同样的命令,不同的字节

实测 · 本机执行输出
  HELLO 3 的回复(前 160 字节): %7⏎$6⏎server⏎$5⏎redis⏎$7⏎version⏎$6⏎8.10.2⏎$5⏎proto⏎:3⏎$2⏎id⏎:7⏎$4⏎mode⏎$10⏎standalone⏎$4⏎role⏎$6⏎master⏎$7⏎modules⏎*1⏎%4⏎$4⏎name⏎$9⏎vectorset⏎$3⏎ver⏎:1⏎$4⏎path
  HGETALL h                  RESP2: *4⏎$2⏎f1⏎$2⏎v1⏎$2⏎f2⏎$2⏎v2⏎                     RESP3: %2⏎$2⏎f1⏎$2⏎v1⏎$2⏎f2⏎$2⏎v2⏎
  SMEMBERS s                 RESP2: *2⏎$1⏎a⏎$1⏎b⏎                                   RESP3: ~2⏎$1⏎a⏎$1⏎b⏎
  ZSCORE z m                 RESP2: $3⏎1.5⏎                                         RESP3: ,1.5⏎
  GET nosuch                 RESP2: $-1⏎                                            RESP3: _⏎
  ZRANGE z 0 -1 WITHSCORES   RESP2: *2⏎$1⏎m⏎$3⏎1.5⏎                                 RESP3: *1⏎*2⏎$1⏎m⏎,1.5⏎

HELLO 3 之后,map(%)、set(~)、double(,)、null(_)这些类型直接出现在回复里。RESP2 里没有这些类型,一律用数组或批量字符串表示,客户端只能按命令名再去解释(比如「HGETALL 的数组是键值成对」)。

类型前缀与 INFO

实测 · 本机执行输出
  INFO 在 RESP3 下的首字节: b'=870\r\ntxt:# ' (= 表示 verbatim string,带 "txt:" 格式标记)

RESP3 的 INFO 用 verbatim string(=),后面带 txt: 格式标记。

体积没有变

实测 · 本机执行输出
  RESP2 2586 字节;RESP3 2586 字节;差 0 字节(RESP3 用一个 %100 头代替 *200 头;元素本身的编码相同)

100 个字段的 HGETALL:RESP2 2586 字节、RESP3 2586 字节。头部 *200 与 %100 一样长,元素本身的编码相同。所以换 RESP3 不会省带宽,收益在客户端更容易解析、不再需要「命令 → 类型」的映射表。

Push:服务器主动推送

实测 · 本机执行输出
  另一个连接改了 str 之后,这个连接收到: >2⏎$10⏎invalidate⏎*1⏎$3⏎str⏎

RESP3 的 Push 类型(>)让服务器在没有对应请求时也能发消息。最常见的用途是客户端缓存(CLIENT TRACKING):读过的 key 被改动时,服务器通过同一条连接推送 invalidate。RESP2 下要做到这一点需要额外开一条连接订阅。

切回 RESP2

实测 · 本机执行输出
  HELLO 2 回复的第一段: *14⏎$6⏎server⏎$5⏎redis⏎$7⏎version⏎$6⏎8.10.2⏎$5⏎proto⏎:2⏎$2⏎i
  之后 HGETALL h: *4⏎$2⏎f1⏎$2⏎v1⏎$2⏎f2⏎$2⏎v2⏎

同一个连接里 HELLO 2 切回 RESP2,之后 HGETALL 又是平铺数组。

分步演示:RESP2 与 RESP3

RESP2 与 RESP3
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。原始 socket 收发;「⏎」表示 \r\n
    • 没有验证:客户端库对 RESP3 的实际支持与性能差异、RESP3 下其它新类型(boolean #、big number ( 、attribute |)的出现场景、CLIENT TRACKING 的广播模式与 NOLOOP 选项
    京ICP备2026067502号-1京公网安备11010502063487号