阅读 563
「进击Redis」十八、不得不知道的Redis 通信协议

「进击Redis」十八、不得不知道的Redis 通信协议

前言

好哥哥们,从上篇保证你没用过 Redis GEO结束后,整个 Redis 系列的数据结构(有些不是数据结构)也就都讲完了。从最开始的五种基础数据类型到后面的像BitmapsHyperLogLogPipeline等等,有没看过的好哥哥可以翻翻我的文章,记得点赞加关注哟(手动比心)。上个阶段总的来说是讲了一些进阶的功能,那接下来的话会是一些关于客户端方面的东西。比如说通信协议、JedisRedisTemplate等,好哥哥们拭目以待吧。
挺好

概述

通信协议

通信协议是指双方实体完成通信或服务所必须遵循的规则和约定。通过通信信道和设备互连起来的多个不同地理位置的数据通信系统,要使其能协同工作实现信息交换和资源共享,它们之间必须具有共同的语言。交流什么、怎样交流及何时交流,都必须遵循某种互相都能接受的规则。这个规则就是通信协议。

Redis 使用协议

  1. 连接: 在 Redis 中客户端与服务端之间的通信协议是在TCP协议之上构建的。
  2. 数据格式: 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 的返回结果类型分为以下五种:

  1. 状态回复:在RESP中第一个字节为+
  2. 错误回复:在RESP中第一个字节为-
  3. 整数回复:在RESP中第一个字节为
  4. 字符串回复:在RESP中第一个字节为$
  5. 多条字符串回复:在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
复制代码

总结

注意点

由于上面讲的协议都是基于请求-响应,但是需要排除以下功能点:

  1. Redis 支持管道操作,不熟悉的好哥哥们可以看看Redis Pipeline 这一篇就够了(整个系列基本基础都有了)。所以客户可以一次发送多个命令,稍后等待回复。
  2. 当 Redis 客户端订阅 Pub/Sub模式的通道时,协议会改变语义变成推送协议,也就是说,客户端不再需要发送命令,因为服务器一旦收到消息就会自动向客户端发送该新消息(对于订阅了通道的客户端)。
  3. Redis 集群使用的是不同的二进制协议来交换节点之间的消息,并不是该协议。

官方文档

Redis 协议规范

碎碎念

针对于 Redis 的通信协议,其实好哥哥们最需要知道的是客户端怎么连接服务器的,另外就是发送和响应的报文格式。在深入的就留给好哥哥们去探索了,看完这个系列我们就不是一个只会get、set的好哥哥了。Redis 系列弄到这的话其实已经有好一些平时我们没有用过的东西了,继续加油吧!!!
加油

本期就到这啦,有不对的地方欢迎好哥哥们评论区留言,另外求关注、求点赞

上一篇: 保证你没用过 Redis GEO

文章分类
后端