会用redis吗?那还不快来了解下redis protocol

      最后更新:2022-07-16 02:27:41 手机定位技术交流文章

      简介

      redis是一个非常优秀的软件,它可以用作内存数据库或者缓存。因为他的优秀性能,redis被应用在很多场合中。

      redis是一个客户端和服务器端的模式,客户端和服务器端是通过TCP协议进行连接的,客户端将请求数据发送到服务器端,服务器端将请求返回给客户端。这样一个请求流程就完成了。

      当然在最开始的时候,因为用的人很少,系统还不够稳定,通过TCP协议传输的数据不规范的。但是当用的人越来越多,尤其是希望开发适用于不同语言和平台的redis客户端的时候,就要考虑到兼容性的问题了。

      这时候客户端和服务器端就需要一个统一的交互协议,对于redis来说这个通用的交互协议就叫做Redis serialization protocol(RESP)。

      RESP在Redis1中,它被引入了版本2,在Redis2.0中是与Redis服务器通信的标准方法。

      也就是说,从Redis 2.After 0,你可以根据Redis协议协议协议开发自己的Redis客户端。

      redis的高级使用

      一般来说,Redis客户端和服务器端由请求-响应模式组成,即客户端向服务器端发送请求,然后从服务器端接收响应结果。

      请求和响应是redis中最简单的用法。熟悉redis的朋友可能会想到了两个redis的高级使用,这两个用法并不是传统意义上的请求-响应模式。

      两种用途是什么?

      第一个是,Redis支持pipline,即管道操作,管道的优点是,Redis客户端可以一次向服务器端发送多个命令,然后等待服务器端返回。

      第二个类型的 redis还支持Pub/Sub,即广播模型,在这种情况下它不是请求和响应模型,而是在Pub/Sub下转换到服务器侧的转发模型。

      雷迪斯管道

      你为什么使用皮普林?

      因为雷迪斯是一个典型的请求响应模型,让我们举一个常见的incr命令例:

      Client: INCR X Server: 1 Client: INCR X Server: 2 Client: INCR X Server: 3 Client: INCR X Server: 4

      事实上客户端只想得到最终的结果,但是每次客户端都需要等待服务器端返回结果之后,才能发送下一次的命令。这样就会导致一个叫做RTT(Round Trip Time)的时间浪费。

      尽管每个RTT的时间并不长,但累积也是一个非常客观的数目。

      那么,你不能把所有的客户端命令一起发送到服务器上吗?这个优化叫做“管道”。

      Piepline 意味着客户端可以继续发送命令到服务器,而不收到服务器的返回。

      上面的命令可以通过pipline修改如下:

      因为Redis服务器支持TCP协议连接,我们可以直接通过连接nc到Redis服务器执行命令。

      在使用pipline的时候有一点要注意,因为Redis服务器将延迟请求的结果到服务器端,直到所有弹簧中的命令都执行并统一返回,所以如果服务器最后返回更多的数据,需要考虑内存使用问题。

      那么,皮普林只是为了减少RTT?

      一个熟悉的操作系统朋友可能听说过用户空间和操作系统空间的概念,从用户输入中读取数据,然后将其写回系统空间中,这涉及一个用户空间开关,在IO操作中,这种空间交换或复制是相当耗时的,如要求及答复频繁,它造成这种频繁的空间变化,这降低了系统的效率。

      使用pipline,可以同时发送多个命令,有效地避免空间交换行为。

      公共/在雷迪斯的下级

      与Pub/Sub相关的命令是 SUBSCRIBE、UNSUBSCRIBE和PUBLISH。

      为什么要用Pub/Sub呢?其主要的目的就是解耦,在Pub/Sub中消息发送方不需要知道具体的接收方的地址,同样的对于消息接收方来说,也不需要知道具体的消息发送方的地址。他们只需要知道关联的主题即可。

      subscribe和publish的命令比较简单,我们举一个例子,首先是客户端subscribe topic:

      然后在另一个终端上调用发布命令:

      您可以看到客户端将收到下列消息:

      RESP protocol

      RESP协议有五个类型: 例如 Strings 、 Errors 、 Integers 、 Bulk Strings 和 Arrays 。

      不同的类型由消息中的第一个字节区分,如下面所示:

      类型 第一个byte
      Simple Strings +
      Errors -
      Integers :
      Bulk Strings $
      Arrays *

      protocol中不同的部分以 "rn" (CRLF)来进行区别。

      Simple Strings

      简单的字符串意味着简单的字符串。

      通常在服务器端返回中使用,此消息的格式是"+"加上文本消息,以"rn"结束。

      例如,如果服务器返回OK,则相应的消息是:

      上面的消息是一个非二进制安全的消息,如果想要发送二进制安全的消息,则可以使用Bulk Strings。

      什么是非二进制安全的消息呢?对于Simple Strings来说,因为消息是以"rn"结尾,所以消息中间不能包含"rn"这两个特殊字符,否则就会产生错误的含义。

      Bulk Strings

      Bulk Strings是二进制安全的。这是因为Bulk Strings包含了一个字符长度字段,因为是根据长度来判断字符长度的,所以并不存在根据字符中某个特定字符来判断是否字符结束的缺点。

      具体而言Bulk Strings的结构是"$"+字符串长度+"rn"+字符串+"rn"。

      例如,OK,如果用大量字符串表示,则显示如下:

      批量字符串也可以包含空字符串:

      当然,它也可以代表不存在的零值:

      RESP Integers

      这是redis中的整数表示,具体的格式是":"+整数+"rn"。

      例如,整数18可以以下列格式表示:

      RESP Arrays

      多个 redis 命令可以显示在阵列中,服务器端返回的多个值也可以显示在阵列中。

      RESP阵列格式是“*” + 阵列中的元素数 + 其他类似的数据。

      所以RESP Arrays是一个复合结构的数据。比如一个数组中包含了两个Bulk Strings:"redis","server"则可以用下面的格式来表示:

      RESP Arrays中的原始不仅可以使用不同类型,还能包含RESP Arrays,也就是array的嵌套:

      为了方便观察,我们将格式化上述信息:

      上面的消息是一个包含三个元素的数组,前面两个元素是Bulk Strings,最后一个是包含一个元素的数组。

      RESP Errors

      最后,RSP也可以显示错误消息。 RESP错误消息格式是"-"+字符串,如下面所示:

      一般来说,“-”之后的第一个字表示一个错误类型,但这是一个传统的要求,而不是 RESP协议的强制要求。

      另外,经过对比,大家可能会发现RESP Errors和Simple Strings是消息格式是差不多的。

      这些不同的消息类型的处理是基于客户端的。

      Inline commands

      如果完全按RESP协议的要求,当我们连接到服务器端的时候需要包含RESP中定义消息的所有格式,但是这些消息中包含了额外的消息类型和回车换行符,所以直接使用协议来执行的话会比较困惑。

      Redis还提供了一些内部命令,即协议命令的简化版本,它排除了消息类型和返回运输替换行。

      让我们以"获取世界"为例,让我们从不同角度来看待这些联系。

      首先,使用 redis-cli连接:

      因为redis-cli是redis的客户端,所以可以直接使用inline command来执行命令。

      如果您使用 telnet,您也可以使用同样的命令获得结果:

      你可以看到返回的结果是"$5rnhellorn".

      如果您要请求使用协议消息的Redis服务器,应该做些什么?

      我们请求的命令是"获取世界",并将其转换为RESP的讯息是:

      让我们尝试通过nc将上面的命令传递到 redis服务器上:

      遗憾的是,我们遇到了错误,所以我们不能直接使用RSP消息格式进行传输吗?当然不是,问题是$一个符号是特殊的符号,我们需要把它翻译成:

      您可以看到输出结果与直用 redis-cli匹配。

      总结

      以上是RESP协议的基本内容和手动使用的一个例子,使用RESP,我们可以根据协议中定义的格式创建一个 redis客户端。

      可能大家又会问了,为什么只是雷迪斯的客户?是否可以用协议创建雷迪斯服务器的末端?答案当然是肯定的,你只需要按照协议发送消息。主要问题是实现 redis服务器端更加复杂,不是那么容易做到的。

      本文由 在线网速测试 整理编辑,转载请注明出处,原文链接:https://www.wangsu123.cn/news/29780.html

          热门文章

          文章分类