专栏
天翼云开发者社区

Redis的网络协议RESP

2024-04-15 16:10:33 21阅读

介绍

参考官方文档

Redis的网络协议,名叫RESP(REdis Serialization Protocol )  ,设计的主要目标:

  • 容易实现
  • 快速解释
  • 容易看懂

 

RESP可以序列化多种数据结构,包括数字、字符串、数组、错误信息等。 而且保证是二进制上的安全性,可以避免网络层面的传输错误,导致数据错误的问题。

 

Redis采取类似命令行的方式去处理请求的。 比如GET KEY1或SET KEY VALUE.  这种方式。  而传统数据库是采取SQL的方式去处理请求, 这时单纯处理SQL解释已经是比较复杂和耗时的。 尤其是复杂或大SQL。   但Redis更简单处理, 用类似命令行的方式隔开参数。 第一个参数对应的命令,后面的参数对应这个命令的参数。 对应网络协议层, 正是字符串类型的数组。 所以Redis解释完网络报文的同时,也等于解释完请求的参数。 这也是Redis执行非常高效的原因之一。

 

RESP版本

RESP现在主流有两个版本:2和3.

早在古老的版本,Redis 1.2 版本之前,有一个原始的版本RESP. 

但在Redis 2.0版本之后,推出了主流的RESP 2版本,基本涵盖了主流的数据类型和表达能力。 

到了Redis 6.0开始,推出了RESP 3协议。 RESP 3协议完全向下兼容RESP 2协议, 同时增加了更多的类型,提供了更好的表达能力。

直到现在2024年,主流默认的协议仍然是RESP 2协议,由于其极通用的使用场景。 但不排除后续一些新增Redis的功能只会出在RESP 3协议上。RESP协议介绍

RESP协议有一些通用的规则:

  • 第一个字节作为类型标识
  • 使用CRLF(即`\r\n`)作为分隔符, 协议的每个部分都是用这两个字节作为分隔符。

下面是协议的类型信息:
 
数据类型 最低的支持版本 分类 第一个字节
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 >
 

Simple strings


简单的字符类型。 以`+` 开始, CRLF(即`\r\n`)结尾,中间是字符内容,例如:
 
+OK\r\n

Simple errors


错误信息, 以`-` 开始, CRLF(即`\r\n`)结尾,中间是字符内容,例如:
-Error message\r\n


 Integers


10进制的整数类型。对应是一个32-bit的interger类型, 格式如下:
:[<+|->]<value>\r\n

  • 第一个字节是`:`
  • 第二个节点可以是+或-号
  • value必须都是数字
  • 结尾是CRLF(即`\r\n`)

Bulk strings


字符类型,可以表达指定长度的字符串,解决了字符内容不能同时有CRLF的问题。一般最大只能支持512mb大小。

格式如下:
$<length>\r\n<data>\r\n


  • 第一个字符是`$`
  • length是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,必须是length长度的字符串
  • 结尾是CRLF(即`\r\n`)

其中length < 0 代表NULL字符串,比如
$-1\r\n
 
长度0的字符串如下:
$0\r\n\r\n

普通字符串如下:
$5\r\nhello\r\n

Arrays


数组类型,可以表达指定长度的数组类型。 数组的内容是嵌套其他任意类型的。 格式如下:
*<number-of-elements>\r\n<element-1>...<element-n>

  • 第一个字符是`*`
  • number-of-elements是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,里面嵌套长度为number-of-elements的任意RESP数据类型

其中length < 0 代表NULL数组,比如
*-1\r\n

长度0的数组如下:
*0\r\n
 

普通数组类型,里面是字符串的如下:
*2\r\n$5\r\nhello\r\n$5\r\nworld\r\n


Nulls


NULL类型,是RESP 3新增的特殊类型, 数据格式如下:
_\r\n

BOOLEANS


布尔类型, 是RESP 3新增的数据类型,数据格式如下:
#<t|f>\r\n

  • 第一个字节是`#`
  • 第二个字节只能是t或f, 代表对应的true或false
  • 结尾是CRLF(即`\r\n`)

Doubles


浮点类, 是RESP 3新增的数据类型,解决了RESP 2只能表达整数的问题。 数据格式如下:
,[<+|->]<integral>[.<fractional>][<E|e>[sign]<exponent>]\r\n

  • 第一个字节是`,`
  • 第二个字节可选是`+`或`-`
  • integral比如是正整数
  • integral后面可选接着`.`和正整数的fractional部分代表小数点后面的数字
  • 可选E或e字节,sign是可选切只能`+`或`-`, exponent部分也只能是正整数
  • 结尾是CRLF(即`\r\n`)

整体看起来是一个普通的浮点数或支持科学计数法的浮点数

比如下面的例子:
,1.23\r\n

也支持一些特殊的场景,比如正无穷,负无穷或没有这个数:
,inf\r\n
,-inf\r\n
,nan\r\n


Big numbers


10进制的整数类型,是RESP 3新增的数据类型。对应是一个64-bit的long类型, 格式如下:
([+|-]<number>\r\n

  • 第一个字节是`(`
  • 第二个节点可以是+或-号
  • number必须都是数字
  • 结尾是CRLF(即`\r\n`)

例如:
(3492890328409238509324850943850943825024385\r\n

Bulk errors


错误信息,是RESP 3新增的数据类型,参考Bulk String设计的错误信息类型。这样就可以表达换行的错误信息。格式如下:
!<length>\r\n<error>\r\n

参考例子:
!21\r\nSYNTAX invalid syntax\r\n

Verbatim strings


字符串类型,是RESP 3新增的数据类型,类似Bulk String, 增加了字符串的编码方式,参考格式如下:
=<length>\r\n<encoding>:<data>\r\n


  • 第一个字节是`=`
  • length是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • encoding比如是3个字节
  • `:` 隔开编码和数据
  • data内容,必须是length-4长度的字符串
  • 结尾是CRLF(即`\r\n`)

参考例子:
=15\r\ntxt:Some string\r\n


Maps


key-value的数据类型,是RESP 3新增的数据类型,类似ARRAY数据,但数量翻倍了。格式如下:
%<number-of-entries>\r\n<key-1><value-1>...<key-n><value-n>

  • 第一个字节是`%`
  • number-of-entries是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,里面嵌套了2 * number-of-entries长度的RESP数据类型,其中单数是KEY,偶数是对应的VALUE

参考如果要表示下面的JSON
{
    "first": 1,
    "second": 2
}

对应的格式如下:
%2\r\n+first\r\n:1\r\n+second\r\n:2\r\n

Sets


类似Array数组格式,是RESP 3新增的数据类型, 只是保证代表的是SET数据类型,数据不会重复。 参考格式如下:
~<number-of-elements>\r\n<element-1>...<element-n>


  • 第一个字节是`~`
  • number-of-elements是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,里面嵌套了number-of-elements个的RESP数据类型

Pushes


PUB/SUB订阅时推送的数据类型,是RESP 3新增的数据类型。RESP 3的协议层面上,支持单个连接复用消息推送。 这时需要使用到的特殊数据类型。 格式类似Array, 格式如下:
><number-of-elements>\r\n<element-1>...<element-n>

  • 第一个字节是`>`
  • number-of-elements是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,里面嵌套了number-of-elements个的RESP数据类型

 

切换网络协议的方法


Redis 6 之后,新增了hello命令,用于参看当前的协议版本,以及支持切换协议版本,命令如下:
HELLO <protocol-version> [optional-arguments]

RESP的其他应用

RESP除了可以Redis的网络协议层,为了简化开发和功能实现,也在地方上面使用了。
Redis用于异常恢复的AOF文件,Redis重启后,需要从AOF文件文件里面读取增量的数据,以恢复完整的数据内容。 其中AOF的内容也是使用RESP格式报文,可以使用文本类工具查询。后续Redis恢复的时候,逻辑也是模拟一个前端连接,重复执行一系列AOF文件里面的命令。 这样也简化了恢复的实现。但这种算是逻辑备份和恢复, 一般来说性能和存储使用率上会比数据库常见的物理备份更差。
  • 2
  • 1
  • 0
0 评论
0/1000
评论(0) 发表评论
叶****伟

叶****伟

6 篇文章 0 粉丝
关注

Redis的网络协议RESP

2024-04-15 16:10:33 21阅读

介绍

参考官方文档

Redis的网络协议,名叫RESP(REdis Serialization Protocol )  ,设计的主要目标:

  • 容易实现
  • 快速解释
  • 容易看懂

 

RESP可以序列化多种数据结构,包括数字、字符串、数组、错误信息等。 而且保证是二进制上的安全性,可以避免网络层面的传输错误,导致数据错误的问题。

 

Redis采取类似命令行的方式去处理请求的。 比如GET KEY1或SET KEY VALUE.  这种方式。  而传统数据库是采取SQL的方式去处理请求, 这时单纯处理SQL解释已经是比较复杂和耗时的。 尤其是复杂或大SQL。   但Redis更简单处理, 用类似命令行的方式隔开参数。 第一个参数对应的命令,后面的参数对应这个命令的参数。 对应网络协议层, 正是字符串类型的数组。 所以Redis解释完网络报文的同时,也等于解释完请求的参数。 这也是Redis执行非常高效的原因之一。

 

RESP版本

RESP现在主流有两个版本:2和3.

早在古老的版本,Redis 1.2 版本之前,有一个原始的版本RESP. 

但在Redis 2.0版本之后,推出了主流的RESP 2版本,基本涵盖了主流的数据类型和表达能力。 

到了Redis 6.0开始,推出了RESP 3协议。 RESP 3协议完全向下兼容RESP 2协议, 同时增加了更多的类型,提供了更好的表达能力。

直到现在2024年,主流默认的协议仍然是RESP 2协议,由于其极通用的使用场景。 但不排除后续一些新增Redis的功能只会出在RESP 3协议上。RESP协议介绍

RESP协议有一些通用的规则:

  • 第一个字节作为类型标识
  • 使用CRLF(即`\r\n`)作为分隔符, 协议的每个部分都是用这两个字节作为分隔符。

下面是协议的类型信息:
 
数据类型 最低的支持版本 分类 第一个字节
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 >
 

Simple strings


简单的字符类型。 以`+` 开始, CRLF(即`\r\n`)结尾,中间是字符内容,例如:
 
+OK\r\n

Simple errors


错误信息, 以`-` 开始, CRLF(即`\r\n`)结尾,中间是字符内容,例如:
-Error message\r\n


 Integers


10进制的整数类型。对应是一个32-bit的interger类型, 格式如下:
:[<+|->]<value>\r\n

  • 第一个字节是`:`
  • 第二个节点可以是+或-号
  • value必须都是数字
  • 结尾是CRLF(即`\r\n`)

Bulk strings


字符类型,可以表达指定长度的字符串,解决了字符内容不能同时有CRLF的问题。一般最大只能支持512mb大小。

格式如下:
$<length>\r\n<data>\r\n


  • 第一个字符是`$`
  • length是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,必须是length长度的字符串
  • 结尾是CRLF(即`\r\n`)

其中length < 0 代表NULL字符串,比如
$-1\r\n
 
长度0的字符串如下:
$0\r\n\r\n

普通字符串如下:
$5\r\nhello\r\n

Arrays


数组类型,可以表达指定长度的数组类型。 数组的内容是嵌套其他任意类型的。 格式如下:
*<number-of-elements>\r\n<element-1>...<element-n>

  • 第一个字符是`*`
  • number-of-elements是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,里面嵌套长度为number-of-elements的任意RESP数据类型

其中length < 0 代表NULL数组,比如
*-1\r\n

长度0的数组如下:
*0\r\n
 

普通数组类型,里面是字符串的如下:
*2\r\n$5\r\nhello\r\n$5\r\nworld\r\n


Nulls


NULL类型,是RESP 3新增的特殊类型, 数据格式如下:
_\r\n

BOOLEANS


布尔类型, 是RESP 3新增的数据类型,数据格式如下:
#<t|f>\r\n

  • 第一个字节是`#`
  • 第二个字节只能是t或f, 代表对应的true或false
  • 结尾是CRLF(即`\r\n`)

Doubles


浮点类, 是RESP 3新增的数据类型,解决了RESP 2只能表达整数的问题。 数据格式如下:
,[<+|->]<integral>[.<fractional>][<E|e>[sign]<exponent>]\r\n

  • 第一个字节是`,`
  • 第二个字节可选是`+`或`-`
  • integral比如是正整数
  • integral后面可选接着`.`和正整数的fractional部分代表小数点后面的数字
  • 可选E或e字节,sign是可选切只能`+`或`-`, exponent部分也只能是正整数
  • 结尾是CRLF(即`\r\n`)

整体看起来是一个普通的浮点数或支持科学计数法的浮点数

比如下面的例子:
,1.23\r\n

也支持一些特殊的场景,比如正无穷,负无穷或没有这个数:
,inf\r\n
,-inf\r\n
,nan\r\n


Big numbers


10进制的整数类型,是RESP 3新增的数据类型。对应是一个64-bit的long类型, 格式如下:
([+|-]<number>\r\n

  • 第一个字节是`(`
  • 第二个节点可以是+或-号
  • number必须都是数字
  • 结尾是CRLF(即`\r\n`)

例如:
(3492890328409238509324850943850943825024385\r\n

Bulk errors


错误信息,是RESP 3新增的数据类型,参考Bulk String设计的错误信息类型。这样就可以表达换行的错误信息。格式如下:
!<length>\r\n<error>\r\n

参考例子:
!21\r\nSYNTAX invalid syntax\r\n

Verbatim strings


字符串类型,是RESP 3新增的数据类型,类似Bulk String, 增加了字符串的编码方式,参考格式如下:
=<length>\r\n<encoding>:<data>\r\n


  • 第一个字节是`=`
  • length是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • encoding比如是3个字节
  • `:` 隔开编码和数据
  • data内容,必须是length-4长度的字符串
  • 结尾是CRLF(即`\r\n`)

参考例子:
=15\r\ntxt:Some string\r\n


Maps


key-value的数据类型,是RESP 3新增的数据类型,类似ARRAY数据,但数量翻倍了。格式如下:
%<number-of-entries>\r\n<key-1><value-1>...<key-n><value-n>

  • 第一个字节是`%`
  • number-of-entries是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,里面嵌套了2 * number-of-entries长度的RESP数据类型,其中单数是KEY,偶数是对应的VALUE

参考如果要表示下面的JSON
{
    "first": 1,
    "second": 2
}

对应的格式如下:
%2\r\n+first\r\n:1\r\n+second\r\n:2\r\n

Sets


类似Array数组格式,是RESP 3新增的数据类型, 只是保证代表的是SET数据类型,数据不会重复。 参考格式如下:
~<number-of-elements>\r\n<element-1>...<element-n>


  • 第一个字节是`~`
  • number-of-elements是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,里面嵌套了number-of-elements个的RESP数据类型

Pushes


PUB/SUB订阅时推送的数据类型,是RESP 3新增的数据类型。RESP 3的协议层面上,支持单个连接复用消息推送。 这时需要使用到的特殊数据类型。 格式类似Array, 格式如下:
><number-of-elements>\r\n<element-1>...<element-n>

  • 第一个字节是`>`
  • number-of-elements是长度,必须是整数
  • 数字后使用CRLF(即`\r\n`)分割
  • 内容,里面嵌套了number-of-elements个的RESP数据类型

 

切换网络协议的方法


Redis 6 之后,新增了hello命令,用于参看当前的协议版本,以及支持切换协议版本,命令如下:
HELLO <protocol-version> [optional-arguments]

RESP的其他应用

RESP除了可以Redis的网络协议层,为了简化开发和功能实现,也在地方上面使用了。
Redis用于异常恢复的AOF文件,Redis重启后,需要从AOF文件文件里面读取增量的数据,以恢复完整的数据内容。 其中AOF的内容也是使用RESP格式报文,可以使用文本类工具查询。后续Redis恢复的时候,逻辑也是模拟一个前端连接,重复执行一系列AOF文件里面的命令。 这样也简化了恢复的实现。但这种算是逻辑备份和恢复, 一般来说性能和存储使用率上会比数据库常见的物理备份更差。
文章来自专栏

中间件随笔

6 篇文章 1 订阅
0 评论
0/1000
评论(0) 发表评论
  • 2
    点赞
  • 1
    收藏
  • 0
    评论