RESP3 不是「更快的协议」,而是「有类型的协议」:客户端能直接知道一个回复是 map、集合还是浮点数,而不必靠命令名去猜。这篇用原始 socket 把同一条命令在 RESP2 与 RESP3 下的字节逐个摆出来,并看它新增的服务器推送。
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 在 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 不会省带宽,收益在客户端更容易解析、不再需要「命令 → 类型」的映射表。
另一个连接改了 str 之后,这个连接收到: >2⏎$10⏎invalidate⏎*1⏎$3⏎str⏎
RESP3 的 Push 类型(>)让服务器在没有对应请求时也能发消息。最常见的用途是客户端缓存(CLIENT TRACKING):读过的 key 被改动时,服务器通过同一条连接推送 invalidate。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 又是平铺数组。