前言
好哥哥们,从上篇保证你没用过 Redis GEO结束后,整个 Redis 系列的
数据结构
(有些不是数据结构)也就都讲完了。从最开始的五种基础数据类型到后面的像Bitmaps
、HyperLogLog
、Pipeline
等等,有没看过的好哥哥可以翻翻我的文章,记得点赞加关注哟(手动比心)。上个阶段总的来说是讲了一些进阶的功能,那接下来的话会是一些关于客户端方面的东西。比如说通信协议、Jedis
、RedisTemplate
等,好哥哥们拭目以待吧。
概述
通信协议
通信协议是指双方实体完成通信或服务所必须遵循的规则和约定。通过通信信道和设备互连起来的多个不同地理位置的数据通信系统,要使其能协同工作实现信息交换和资源共享,它们之间必须具有共同的语言。交流什么、怎样交流及何时交流,都必须遵循某种互相都能接受的规则。这个规则就是通信协议。
Redis 使用协议
- 连接: 在 Redis 中客户端与服务端之间的通信协议是在
TCP
协议之上构建的。 - 数据格式: Redis 制定了
RESP
(REdis Serialization Protocol,Redis 序列化协议)实现客户端与服务端的正常交互,这种协议简单高效、既能够被机器解析、又容易被人类识别。
RESP 协议
该协议是专门为 Redis 设计的,可以序列化不同的数据类型,如integers
(整数),strings
(字符串),arrays
(数组)。它还使用了一个特殊的类型来表示errors
(错误)。请求以字符串数组的形式来表示要执行命令的参数从客户端发送到 Redis 服务器。Redis 使用command-specific
(命令特有)数据类型作为回复。
RESP
协议是二进制安全的,并且不需要处理从一个进程传输到另一个进程的块数据的大小,因为它使用prefixed-length
(前缀长度)的方式来传输块数据的。
需要注意的是该协议是仅用于 客户端 - 服务器(Client-Server)的通信。 Redis 集群使用不同的二进制协议来交换节点之间的消息。
发送命令格式
RESP 的规定一条命令的格式如下,CRLF 代表\r\n
。
*< 参数数量 > CRL
$< 参数 1 的字节数量 > CRLF
< 参数 1> CRLF
...
$< 参数 N 的字节数量 > CRLF
< 参数 N> CRLF
以set hello world
这条命令举例
## 参数数量为3个,因此第一行为:
*3
## 参数字节数分别是355,因此后面几行为:
$3
SET
$5
hello
$5
world
需要注意的是,上面只是格式化显示的结果,实际传输格式为如下代码
*3\r\n$3\r\nSET\r\n$5\r\nhello\r\n$5\r\nworld\r\n
响应结果格式
Redis 的返回结果类型分为以下五种:
- 状态回复:在
RESP
中第一个字节为+
。 - 错误回复:在
RESP
中第一个字节为-
。 - 整数回复:在
RESP
中第一个字节为:
。 - 字符串回复:在
RESP
中第一个字节为$
。 - 多条字符串回复:在
RESP
中第一个字节为*
。
在redis-cli
只能看到最终的执行结果(例如执行set hello world
,返回结果是OK
,并没有看到类似于+
符合),那是因为redis-cli
本身就是按照RESP
进行结果解析的,所以看不到中间结果,redis-cli.c 源码对命令结果的解析结构如下:
static sds cliFormatReplyTTY(redisReply *r, char *prefix) {
sds out = sdsempty();
switch (r->type) {
case REDIS_REPLY_ERROR:
// 处理错误回复
case REDIS_REPLY_STATUS:
// 处理状态回复
case REDIS_REPLY_INTEGER:
// 处理整数回复
case REDIS_REPLY_STRING:
// 处理字符串回复
case REDIS_REPLY_NIL:
// 处理空
case REDIS_REPLY_ARRAY:
// 处理多条字符串回复
return out;
}
那好哥哥要问了,怎么才能看到 Redis 服务端返回的“真正”结果呢?可以使用 nc 命令、telnet 命
令、甚至写一个 socket 程序进行模拟。以nc
命令举个栗子
## 连接到Redis
nc 127.0.0.1 6379
## 执行set命令
set hello world
## 状态回复返回
+OK
## 执行一个不存在的命令
sethx
## 错误回复
-ERR unknown command 'sethx'
## 执行加法操作
incr counter
## 整数回复
:1
## 执行取值操作
get hello
## 字符串回复
$5
world
## 批量设置多个键值对
mset java jedis python redis-py
## 批量获取mget
mget java python
## 返回结果条数
*2
##字符串回复
$5
jedis
$8
redis-py
## 如果key不存在,返回的就是 $-1
get not_exist
## 无论是字符串回复还是多条字符串回复,如果有nil值,那么会返回 $-1。
$-1
总结
注意点
由于上面讲的协议都是基于请求-响应,但是需要排除以下功能点:
- Redis 支持管道操作,不熟悉的好哥哥们可以看看Redis Pipeline 这一篇就够了(整个系列基本基础都有了)。所以客户可以一次发送多个命令,稍后等待回复。
- 当 Redis 客户端订阅
Pub/Sub
模式的通道时,协议会改变语义变成推送协议,也就是说,客户端不再需要发送命令,因为服务器一旦收到消息就会自动向客户端发送该新消息(对于订阅了通道的客户端)。 - Redis 集群使用的是不同的二进制协议来交换节点之间的消息,并不是该协议。
官方文档
![](/qrcode.jpg)
碎碎念
针对于 Redis 的通信协议,其实好哥哥们最需要知道的是客户端怎么连接服务器的,另外就是发送和响应的报文格式。在深入的就留给好哥哥们去探索了,看完这个系列我们就不是一个只会get、set
的好哥哥了。Redis 系列弄到这的话其实已经有好一些平时我们没有用过的东西了,继续加油吧!!!
本期就到这啦,有不对的地方欢迎好哥哥们评论区留言,另外求关注、求点赞