快捷搜索:  汽车  科技

redis核心难点(Redis为什么这么快)

redis核心难点(Redis为什么这么快)" OK\r\n" 想要发送二进制安全的字符串,需要用RESP的块字符串。当redis返回了一个简单字符串的时候,客户端库需要给调用者返回“ ”号(不含)之后CRLF之前(不含)的字符串。用如下方法编码:一个“ ”号后面跟字符串,最后是“\r\n”,字符串里不能包含"\r\n"。简单字符串用来传输比较短的二进制安全的字符串。例如很多redis命令执行成功会返回“OK”,用RESP编码就是5个字节:在 RESP 中,某些数据的类型取决于第一个字节:此外,RESP 能够使用稍后指定的批量字符串或数组的特殊变体来表示 Null 值。在 RESP 中,协议的不同部分总是以“\r\n”(CRLF)终止。下面只简单介绍字符串的编码方式和错误的编码方式,详情可以查看 Redis 官网对 RESP 进行了详细的说明。

小总结

一句话描述 IO 多路复用在 Redis 中的应用:Redis 将所有产生事件的套接字都放到一个队列里面,以有序、同步、每次一个套接字的方式向文件事件分派器传送套接字,文件事件分派器根据套接字对应的事件选择响应的处理器进行处理,从而实现了高效的网络请求。

Redis的自定义协议

Redis客户端使用RESP(Redis的序列化协议)协议与Redis的服务器端进行通信。 它实现简单,解析快速并且人类可读。

RESP 支持以下数据类型:简单字符串、错误、整数、批量字符串和数组。

RESP 在 Redis 中用作请求-响应协议的方式如下:

  • 客户端将命令作为批量字符串的 RESP 数组发送到 Redis 服务器。
  • 服务器根据命令实现以其中一种 RESP 类型进行回复。

在 RESP 中,某些数据的类型取决于第一个字节:

  • 对于简单字符串,回复的第一个字节是“ ”
  • 对于错误,回复的第一个字节是“-”
  • 对于整数,回复的第一个字节是“:”
  • 对于批量字符串,回复的第一个字节是“$”
  • 对于数组,回复的第一个字节是“*”

此外,RESP 能够使用稍后指定的批量字符串或数组的特殊变体来表示 Null 值。在 RESP 中,协议的不同部分总是以“\r\n”(CRLF)终止。

下面只简单介绍字符串的编码方式和错误的编码方式,详情可以查看 Redis 官网对 RESP 进行了详细的说明。

简单字符串

用如下方法编码:一个“ ”号后面跟字符串,最后是“\r\n”,字符串里不能包含"\r\n"。简单字符串用来传输比较短的二进制安全的字符串。例如很多redis命令执行成功会返回“OK”,用RESP编码就是5个字节:

" OK\r\n"

想要发送二进制安全的字符串,需要用RESP的块字符串。当redis返回了一个简单字符串的时候,客户端库需要给调用者返回“ ”号(不含)之后CRLF之前(不含)的字符串。

RESP错误

RESP 有一种专门为错误设计的类型。实际上错误类型很像RESP简单字符串类型,但是第一个字符是“-”。简单字符串类型和错误类型的区别是客户端把错误类型当成一个异常,错误类型包含的字符串是异常信息。格式是:

"-Error message\r\n"

有错误发生的时候才会返回错误类型,例如你执行了一个对于某类型错误的操作,或者命令不存在等。当返回一个错误类型的时候客户端库应该发起一个异常。下面是一个错误类型的例子

-ERR unknown command 'foobar' -WRONGTYPE Operation against a key holding the wrong kind of value

“-”号之后空格或者换行符之前的字符串代表返回的错误类型,这只是惯例,并不是RESP要求的格式。例如ERR是一般错误,WRONGTYPE是更具体的错误表示客户端的试图在错误的类型上执行某个操作。这个称为错误前缀,能让客户端更方便的识别错误类型。

客户端可能为不同的错误返回不同的异常,也可能只提供一个一般的方法来捕捉错误并提供错误名。但是不能依赖客户端提供的这些特性,因为有的客户端仅仅返回一般错误,比如false。

高性能 Redis 协议分析器

尽管 Redis 的协议非常利于人类阅读, 定义也很简单, 但这个协议的实现性能仍然可以和二进制协议一样快。

因为 Redis 协议将数据的长度放在数据正文之前, 所以程序无须像 JSON 那样, 为了寻找某个特殊字符而扫描整个 payload , 也无须对发送至服务器的 payload 进行转义(quote)。

程序可以在对协议文本中的各个字符进行处理的同时, 查找 CR 字符, 并计算出批量回复或多条批量回复的长度, 就像这样:

#include <stdio.h> int main(void) { unsigned char *p = "$123\r\n"; int len = 0; p ; while(*p != '\r') { len = (len*10) (*p - '0'); p ; } /* Now p points at '\r' and the len is in bulk_len. */ printf("%d\n" len); return 0; }

得到了批量回复或多条批量回复的长度之后, 程序只需调用一次 read 函数, 就可以将回复的正文数据全部读入到内存中, 而无须对这些数据做任何的处理。在回复最末尾的 CR 和 LF 不作处理,丢弃它们。

Redis 协议的实现性能可以和二进制协议的实现性能相媲美, 并且由于 Redis 协议的简单性, 大部分高级语言都可以轻易地实现这个协议, 这使得客户端软件的 bug 数量大大减少。

冷知识:redis到底有多快?

在成功安装了Redis之后,Redis自带一个可以用来进行性能测试的命令 redis-benchmark,通过运行这个命令,我们可以模拟N个客户端同时发送请求的场景,并监测Redis处理这些请求所需的时间。

根据官方的文档,Redis经过在60000多个连接中进行了基准测试,并且仍然能够在这些条件下维持50000 q/s的效率,同样的请求量如果打到MySQL上,那肯定扛不住,直接就崩掉了。也是因为这个原因,Redis经常作为缓存存在,能够起到对数据库的保护作用。

redis核心难点(Redis为什么这么快)(1)

官方给的Redis效率测试统计图[1](横坐标是连接数量,纵坐标是QPS)

可以看出来啊,Redis号称十万吞吐量确实也没吹牛,以后大家面试的时候也可以假装不经意间提一嘴这个数量级,发现很多人对“十万级“、”百万级“这种量级经常乱用,能够比较精准的说出来也是一个加分项呢。

redis核心难点(Redis为什么这么快)(2)

我是敖丙,你知道的越多,你不知道的越多,感谢各位人才的:点赞收藏评论,我们下期见!


文章持续更新,私信【资料】有我准备的一线大厂面试资料和简历模板,有大厂面试完整考点。

猜您喜欢: