当前位置:首页 > 问答 > 正文

once用Redis搞快速响应系统,聊聊redis的respp那些事儿

根据网络上关于Redis协议RESP的常见技术讨论博客、Redis官方文档摘要以及相关开发者社区问答整理而成)

那次我们团队接了个急活儿,要做一个实时排行榜,要求用户每次刷新页面,名次和积分都要立刻更新,延迟不能超过50毫秒,要是用传统数据库,每次排名都得“SELECT ... ORDER BY ... LIMIT”,数据库肯定扛不住,慢得跟蜗牛一样,这时候,老张拍板说:“用Redis吧,它的RESP协议能让响应飞起来。”

我当时就纳闷了,RESP是啥?听起来很高深,老张笑着解释说,别被缩写吓到,其实它就是Redis和咱们的应用程序“说话”的一套规矩,全称叫Redis序列化协议,你可以把它想象成两个人打电话,如果双方没有约定好先说什么后说什么,你说一句“我饿了”,他回一句“今天天气不错”,那这天就没法聊了,RESP就是确保Redis和客户端能高效、无误沟通的“语言手册”。

once用Redis搞快速响应系统,聊聊redis的respp那些事儿

这套协议设计得非常聪明,它用了最简单的方式来区分不同部分的数据,它规定了五种基本“句型”:

第一种是最简单的单行字符串,以一个加号“+”开头,后面跟着字符串内容,以“\r\n”结束,比如Redis操作成功了,它可能会回复一个"+OK\r\n",客户端看到“+”开头,就知道这是个好消息,直接读后面的“OK”就行了。

once用Redis搞快速响应系统,聊聊redis的respp那些事儿

第二种是错误信息,以减号“-”开头,比如你发了个Redis不认识的命令,它就会回复"-ERR unknown command'\r\n",客户端一看到“-”,心里就咯噔一下,知道出错了,赶紧把错误信息记录下来或者告诉用户。

第三种是整数,以冒号“:”开头,比如你问Redis数据库里有多少个key,用DBSIZE命令,它可能回复":1000\r\n",表示有1000个,这种格式对于返回一些数量、状态码特别方便。

once用Redis搞快速响应系统,聊聊redis的respp那些事儿

第四种是批量字符串,以美元符号“$”开头,这是最常用的一种,专门用来传输可能比较长的字符串,比如一个键对应的值,它先告诉对方这个字符串有多长,$5\r\nhello\r\n",意思是后面跟着一个长度是5的字符串“hello”,如果值不存在,它会用“$-1\r\n”来表示空值,这种先报长度再给内容的方式,让接收方可以提前准备好合适大小的内存来接收,不会出错。

第五种是数组,以星号“”开头,当需要返回多个数据时,比如执行LRANGE命令获取一个列表里的多个元素,Redis就会用数组格式。3\r\n$5\r\nhello\r\n$5\r\nworld\r\n$1\r\n!\r\n",这表示一个包含三个元素的数组,第一个是字符串“hello”,第二个是“world”,第三个是“!”。

老张说,RESP的精髓就在于“简单”和“可预知”,客户端发送一个命令时,也是按照数组格式组织的,比如我们发命令“SET name Alice”,实际发送的就是"3\r\n$3\r\nSET\r\n$4\r\nname\r\n$5\r\nAlice\r\n",Redis服务器收到后,一看星号“”知道这是个数组,数字3表示有三个元素,然后它就按顺序解析出三个批量字符串“SET”、“name”、“Alice”,这样就明白你要干什么了。

因为格式固定、简单,Redis解析起来就特别快,几乎不费什么力气,它不用像解析XML或JSON那样,还得去处理复杂的标签、括号嵌套,这种高效解析是Redis能达到微秒级响应速度的一个重要原因,RESP是文本协议,虽然不像二进制协议那么省空间,但特别容易让人读懂和调试,你用普通的Telnet或者nc命令就能直接和Redis服务器“对话”,手动发命令,这对于排查问题来说太友好了。

我们用了Redis的有序集合来实现那个排行榜,每次更新积分和获取排名,客户端和Redis之间就是通过这种简洁明了的RESP协议来回沟通,结果当然是圆满成功,系统响应速度一直稳定在毫秒级,经过那次项目,我算是明白了,很多听起来高大上的技术,核心思想往往就是这么直观和朴实,RESP这事儿,说白了就是给数据穿上一件件带有明确标签的“衣服”,让收发双方都能毫不费力地认出谁是谁,从而实现了高效的协作。