听说Redis协议很简单,那今天就抓个包来一起看看吧。
RESP是什么
![图片[1]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-32.png?imageMogr2/format/webp/interlace/1/quality/100)
Redis 的序列化协议, 是一种二进制协议,支持多种数据类型,其中,数据的第一个字节(First byte)决定其类型,使用( CRLF
\r\n
)作为协议的终止符。特点:易于实现,快速解析,可直接阅读
目前有 RESP2 和 RESP3(Redis6开始) 两个版本。
支持这么多种类型 👇
RESP data type | Minimal protocol version | Category | First byte |
---|---|---|---|
Simple strings | RESP2 | Simple | + |
Simple Errors | RESP2 | Simple | - |
Integers | RESP2 | Simple | : |
Bulk strings | RESP2 | Aggregate | $ |
Arrays | RESP2 | Aggregate | * |
Nulls | RESP3 | Simple | _ |
Booleans | RESP3 | Simple | # |
Doubles | RESP3 | Simple | , |
Big numbers | RESP3 | Simple | ( |
Bulk errors | RESP3 | Aggregate | ! |
Verbatim strings | RESP3 | Aggregate | = |
Maps | RESP3 | Aggregate | % |
Sets | RESP3 | Aggregate | ~ |
Pushes | RESP3 | Aggregate | > |
下面开始会用 Linux 上的 nc 命令 和 Wireshark 来抓包部分命令进行分析。
简单字符串 和 整数
# 简单字符串
+OK\r\n
# 整数
:[<+|->]<value>\r\n
比如
:0\r\n和:1000\r\n
通过 nc 命令,连接到 Redis Server,可以清楚看到每一个指令。
![图片[2]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-33.png?imageMogr2/format/webp/interlace/1/quality/100)
:
表示整数
![图片[3]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-34.png?imageMogr2/format/webp/interlace/1/quality/100)
简单错误
-Error message\r\n
比如
-ERR unknown command 'asdf'
-WRONGTYPE Operation against a key holding the wrong kind of value
![图片[4]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-35.png?imageMogr2/format/webp/interlace/1/quality/100)
Bulk strings大字符串
$<length>\r\n<data>\r\n
比如
$5\r\nhello\r\n
$0\r\n\r\n
大字符串,支持 512 MB,可以通过 redis.conf 中的 proto-max-bulk-len 修改
![图片[5]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-36.png?imageMogr2/format/webp/interlace/1/quality/100)
针对 null 的情况
$-1\r\n
resp2的情况
![图片[6]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-37.png?imageMogr2/format/webp/interlace/1/quality/100)
从 Wireshark 中抓包可以看到,Response 5 个字节,$-1\r\n
![图片[7]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-38.png?imageMogr2/format/webp/interlace/1/quality/100)
resp3 设计了 Nulls 类型来处理 null
![图片[8]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-39.png?imageMogr2/format/webp/interlace/1/quality/100)
这里需要通过 hello 去升级协议,但是我 window 上 redis-cli 的版本比较低,不支持,会报错。
折腾了好一会,感觉在 window 上装这个 redis 超级麻烦,索性用 Nginx 去代理转发。
因为 Wireshark 装在 window 上,但是这个 redis 跑在虚拟机上的,如果直接连接 redis-server ,Wireshark 抓不到 VMnet8 网卡上的流量。
启用Nginx代理TCP流量
![图片[9]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-40.png?imageMogr2/format/webp/interlace/1/quality/100)
redis-cli 针对 null 解析成 nil 表示。
![图片[10]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-41.png?imageMogr2/format/webp/interlace/1/quality/100)
可以看到返回 3 个字节,_\r\n
刚好对上
![图片[11]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-42.png?imageMogr2/format/webp/interlace/1/quality/100)
数组
*
表示数组长度,这里是 6
$
是字符串长度,比如 name 是 4.
![图片[12]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-43.png?imageMogr2/format/webp/interlace/1/quality/100)
![图片[13]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-44.png?imageMogr2/format/webp/interlace/1/quality/100)
再比如 list 类型的。
lrange mylist 0 -1
![图片[14]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-45.png?imageMogr2/format/webp/interlace/1/quality/100)
![图片[15]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-46.png?imageMogr2/format/webp/interlace/1/quality/100)
Set
![图片[16]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-47.png?imageMogr2/format/webp/interlace/1/quality/100)
升级到 resp3 后,第一个字节是 ~
,对应上面的表格
![图片[17]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-48.png?imageMogr2/format/webp/interlace/1/quality/100)
没升级的情况还是数组的表示方式 *
![图片[18]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-49.png?imageMogr2/format/webp/interlace/1/quality/100)
用 Redis-cli 发出去的 Request 请求也是一样,比如这里 *2\r\n$8\r\nsmembers\r\n$5\r\nmyset\r\n
,刚好 29 个字节。
![图片[19]-Redis的RESP协议抓包分析-编程社](https://cos.bianchengshe.com/wp-content/uploads/2024/05/image-50.png?imageMogr2/format/webp/interlace/1/quality/100)
参考文章
https://redis.io/docs/latest/develop/reference/protocol-spec/ (官网文档)
https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md (官网文档)
暂无评论内容