RESP协议

redis 官方网站 https://redis.io/
redis 官网文档 https://redis.io/docs/
redis 官网 RESP相关 https://redis.io/docs/reference/protocol-spec/
菜鸟教程 https://www.runoob.com/redis/redis-intro.html

redis 简介

redis数据库,REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)

有五种基本的数据结构

  1. string(字符串)
  2. hash(散列)
  3. list(链表)
  4. set(集合)
  5. sort set(有序集合)

几种基本数据类型存储方式以及应用场景

  1. 字符串 (String):
  • 存储方式:Redis的字符串是动态字符串,类似于Java中的ArrayList。内部实现为一个结构体,其中包含长度(len)、空间(free)和字节数组(buf)。在字符串长度小于1M时,每次扩容都是加倍现有空间,超过1M后,每次扩容增加1M空间。
  • 应用场景:除了存储普通字符串外,还经常用作各种类型的数值的存储,例如计数器、分布式锁的设置等。
  1. 哈希 (Hash):
  • 存储方式:Hash类型在底层是通过哈希表实现的,当哈希集合中的元素个数和元素大小都比较小时,Redis会使用一种称作ziplist(压缩列表)的紧凑数据结构来存储哈希。当数据量增加之后,Redis会改用更标准的哈希表结构来存储键值对。
  • 应用场景:适用于存储对象,可以用来表示用户的各种属性等。
  1. 链表 (List):
  • 存储方式:List类型在底层主要是通过双向链表实现的,同样会在元素个数较少的情况下使用ziplist作为底层结构,节约内存空间。当列表项的数量或者大小超过预设的阈值时,会改用双向链表。
  • 应用场景:适合用于实现队列和栈,以及在添加或删除元素时保持高性能。
  1. 集合 (Set):
  • 存储方式:Set的底层同样是使用哈希表来实现的,这使得集合中的每个元素都是唯一的且没有顺序。在元素较少的情况下,会使用类似于哈希的ziplist存储结构,以优化内存使用。
  • 应用场景:适合储存不重复的元素集合,例如标签、朋友关系等。
  1. 有序集合 (Sorted Set):
  • 存储方式:有序集合是一种排序的集合,底层实际上是通过跳跃表(skip list)和哈希表共同实现的。跳跃表用于按分数排序和获取排名,而哈希表则用于存储成员到分数的映射。
  • 应用场景:适用于需要按照一定顺序排列元素的场景,如排行榜。

redis 应用场景与底层实现,命令结构不再本文档重点关注范围内,因此不在这里赘述

前后端通讯协议

redis数据库前后端通讯使用RESP (Redis serialization protocol )协议,是专门为redis设计的一种文本传输协议,在redis 1.2中开始使用该协议,redis2中升级为 RESP2,redis6.0 引入了RESP3,RESP3 是RESP2的超集。

协议简介

RESP 大多数情况下是依托于tcp协议的,虽然从技术角度讲,该协议并不是面向tcp的协议,默认的监听端口是6379

RESP本质上是一种串行协议,支持很多种消息类型,其每种消息的第一个字段,指示了这种消息的类型。由于他本身是一种文本通讯协议,跟传统的协议不同的是,每种消息的大小,长度,都是不固定的,包括其标识每条消息的长度信息,以及对应的载荷信息,长度都是不固定的,位置在报文中也不固定,唯一能确定消息结构的,只有每条消息的第一个字段。

虽然redis支持多种不同数据类型,但对于用户是完全透明的,因此在RESP协议的设计中,也考虑到了这一点,设计的相对较为简单,其主体思路就是将命令拆分整合,发送给服务端或者客户端,由服务端或者客户端去解析这些报文。

消息类型

数据类型引入版本种类第一个字节
simple strtingRESP2simple+
simple errorsRESP2simple-
integersRESP2simple:
bulk stringRESP2aggregate$
arrayRESP2aggregate*
NullsRESP3simple-
booleansRESP3simple#
DoublesRESP3simple,
Big numberRESP3simple(
Bulk errorsRESP3aggregate!
verbatim stringRESP3aggregate=
MapsRESP3aggregate%
setsRESP3aggregate~
pushesRESP3aggregate>

字段说明

  • simple string
    简单字符串,常用于服务端相应消息,消息结构为 “+” \r\n
    示例:
+OK\r\n

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • simple errors
    大多数情况下是服务端发送给客户端的消息(目前没见过客户端发送的err消息不确定会不会有)消息结构为 “-”\r\n
    和简单消息结构相同,只不过前缀字符从 “+” 变成了 “-”
    示例:
-Error message\r\n
-ERR unknown command 'asdf'
-WRONGTYPE Operation against a key holding the wrong kind of value

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • Intergers
    十进制 64位整数,在协议中也是以字符串的形式存在的,其基本的数据格式为
:[<+|->]<value>\r\n

样例:

:0\r\n
:100\r\n

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • Bulk String
    Bulk String 表示一个二级制字符串,这个字符串长度并没有限制,但是redis规定字符串长度最长是512MB。
    Bulk String 可以在array中出现,也可以单独出现,引导字符为 “$”。
    基本格式为
$<length>\r\n<data>\r\n

样例

$5\r\nhello\r\n
# 空字符
$0\r\n\r\n

在这里插入图片描述

  • Array

这个类型主要是将redis命令以及服务端返回的数据以array成员的形式进行传输,引导字符为 “*”,命令格式为

*<number of elements>\r\n<element1>\r\n<element2>\r\n……<element number>\r\n

样例:

*0\r\n
*2\r\n$5\r\nhello\r\n$5\r\nworld\r\n

在这里插入图片描述

  • NULL
    空数据 不存在任何数值
    首字节用 “_” 引导

resp2中有 空bulk string, 还有空 array,因为是多元参数,导致在实现上有所冗余,在resp3中引入了这个NULL类型,用来解决这个问题

_\r\n
  • Booleans, Doubles, Big Numbers
    这三种类型同样是resp3引入的新类型,用于补充resp2中缺少的数据类型,用法类似于Intergers
// Booleans "#"引导
#<t|f>\r\n
// double ","引导
,[<+|->]<integral>[.<fractional>][<E|e>[sign]<exponent>]\r\n #E 科学计数法
// 正负无穷大,无数据
,inf\r\n
,-inf\r\n
,nan\r\n
// 超大整型
([+|-]<number>\r\n
  • Bulk errors
    这个字段也是对resp2的补充, 前导字符是 “!”, 消息格式
!<length>\r\n<error>\r\n

样例:

!21\r\nSYNTAX invalid syntax\r\n
  • MAPS

RESP3引入的数据类型,跟array类似,使用"%" 引导,"%"字符后跟着一个数字,用以标识该maps中有多少个键值对,比如有一个键值对,则%后数字则为1,基本数据格式为:

%<number-of-entries>\r\n<key-1><value-1>...<key-n><value-n>

样例

%2\r\n
+first\r\n
:1\r\n
+second\r\n
:2\r\n

报文样例:
在这里插入图片描述

  • Sets

这个主要是由服务端返回给客户端的,由 ‘~’ 引导,首先是返回的数值数量,后面跟着的就是内容

报文结构

~<number-of-elements>\r\n<element-1>...<element-n>

样例

在这里插入图片描述

  • Pushes

RESP的推送包含带外数据。它们是协议请求-响应模型的例外,并为连接提供通用的推送模式。
报文结构与 sets 相同, 由 '>'引导

><number-of-elements>\r\n<element-1>...<element-n>

其他说明

  1. RESP协议中simple类型与aggregate类型,应该怎么理解

在Redis Serialization Protocol (RESP) 中,数据类型主要分为两类:简单数据类型(simple data types)和聚合数据类型(aggregate data types)。

  • 简单数据类型(Simple Data Types)
  • 聚合数据类型(Aggregate Data Types)

简单数据类型通常用于传输单个值,而聚合数据类型则用于传输包含多个值的复杂结构,例如列表、集合等。RESP协议通过这些数据类型的设计允许Redis传递丰富的数据结构,同时保持了协议的简洁性和效率。

  1. 对于超长的redis数据,resp是如何处理的

resp协议是基于文本的协议,当一个报文无法承载完整的数据时,剩下的报文就会直接放到下一个报文中,而下一条报文不会重新设置报文数据头,也不会有报文截断标识,每一条数据结束的标识只有\r\n。举例说明:

在这里插入图片描述

在这里插入图片描述

  1. redis 管道命令是如何解决的

每一条resp报文,可以有多条array,对于多条命令管道执行,第一个array为multi 最后一个array则为 exec,中间的array则为需要执行的各种命令,报文示例如下

在这里插入图片描述

  1. redis 对resp协议的支持
    1. redis数据库由1.2版本引入resp协议,2.0版本引入了resp2,5.0以上的版本则支持了resp3协议
    2. resp3 协议使用客户端需要先向服务端发送hello 3 消息,才能使用resp3协议
  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

望晓天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值