twemproxyRedis协议解析探索——剖析twemproxy代码正编

这篇文章会对twemproxyRedis协议解析代码部分进行一番简单的分析,同时给出twemproxy目前支持的所有Redis命令。在这篇文章开始前,我想大家去简单地理解一下有限状态机,当然不理解也是没有问题的,有限状态机仅仅能帮助我们更好地理解twemproxyRedis协议解析代码部分。

redis 协议

这边我们首先需要简单介绍一下redis协议。参考自https://redis.io/topics/protocol

redis协议即RESP 的数据类型有5类,简单字符串、错误、整数、大字符串以及数组

每一行RESP都以"\r\n" (CRLF)结尾,每一种数据类型都有一个唯一的标识符作为开头,。

这里假设 [string(len)]为长度为len的字符长度,[string]为长度为任意的的字符长度,[int]为整数

简单字符串

这种数据类型往往表示一种正确的信息,其标识符为+,格式为

+[string]\r\n

如对于一个操作类命令操作成功的回复是

+OK\r\n

错误

这种数据类型往往表示一种错误的信息, 其标识符为-,格式为

-[string]\r\n

如对于一个操作类命令操作错误的回复可能是

-ERR unknown command ‘foobar‘\r\n

整数

这种数据类型往往表示一个整数, 其标识符为:,格式为

:[int]\r\n

如对于一些数据类命令的回复可能是

:1000\r\n

大字符串

这种数据类型往往表示一个有长度len信息的字符串, 其标识符为$,格式为 :

$len\r\n

[string(len)]\r\n

如对于一个命令set的包就是

3\r\n

set\r\n

数组

这种数据类型往往数量为k信息所有类型混合的数据,并不一定要同一类型, 其标识符为*,格式为 :

*k\r\n

k个[简单字符串、错误、整数、大字符串或数组]

如对于一个命令

set skey value

的包就是 :

*3\r\n

$3\r\n

set\r\n

$4\r\n

skey\r\n

$5\r\n

value\r\n

如回复包

*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n

redis请求包解析

在proto/nc_redis.c中的redis_parse_req函数解析了redis请求包

redis请求包有限状态机的符号图如下图所示:

redis请求包符号表转化图

写成正式格式的set skey value一样的是*3\r\n$3\r\nset\r\n$4\r\nskey\r\n$5\r\nvalue\r\n。对于这个set命令就是以SW_REQ_TYPE(set),SW_KEY(skey ),SW_ARG1(value)组成的,redis命令的基本的组成如下:SW_REQ_TYPE SW_KEY [SW_ARG1] [SW_ARG2] [SW_ARG3] ... [SW_ARGN]([]里的可以出现或者不出现,视SW_REQ_TYPE 的类型所示),SW_KEY 可以是是多个。

如果是只有SW_KEY 的是满足函数redis_argx的命令,带有SW_ARG1的是满足函数redis_arg1以及redis_argkvx的命令,带有SW_ARG2的是满足函数redis_arg2的命令,带有满足SW_ARG3的是函数redis_arg3的命令,带有SW_ARGN的是满足函数redis_argn以及redis_argeval的命令,为此我们可以画出代码state之间的转化关系

 1    enum {
 2         SW_START,
 3         SW_NARG,
 4         SW_NARG_LF,
 5         SW_REQ_TYPE_LEN,
 6         SW_REQ_TYPE_LEN_LF,
 7         SW_REQ_TYPE,
 8         SW_REQ_TYPE_LF,
 9         SW_KEY_LEN,
10         SW_KEY_LEN_LF,
11         SW_KEY,
12         SW_KEY_LF,
13         SW_ARG1_LEN,
14         SW_ARG1_LEN_LF,
15         SW_ARG1,
16         SW_ARG1_LF,
17         SW_ARG2_LEN,
18         SW_ARG2_LEN_LF,
19         SW_ARG2,
20         SW_ARG2_LF,
21         SW_ARG3_LEN,
22         SW_ARG3_LEN_LF,
23         SW_ARG3,
24         SW_ARG3_LF,
25         SW_ARGN_LEN,
26         SW_ARGN_LEN_LF,
27         SW_ARGN,
28         SW_ARGN_LF,
29         SW_SENTINEL
30     } state;

redis请求包状态转化图

通过这种方式twemproxy解析了redis的请求包,首先解析了每个包的类型,然后将每一个key的开始、结束指针记录到相应的包中,用来完成切片操作。这种有限状态机的方式不仅比正则表达式解析速度快,而且代码较为清晰。

redis回复包解析

在proto/nc_redis.c中的redis_parse_rsp函数解析了redis请求包

这里用过符号区分了redis协议的回复包类型,这里的符号的意思就是指在上面《redis协议》章节中提到的符号

SW_STATUS是简单字符串

SW_ERROR是错误

SW_INTEGER是整数

SW_BULK是大字符串

SW_MULTIBULK是数组

下面是redis协议的解析状态:

 1    enum {
 2         SW_START,
 3         SW_STATUS,
 4         SW_ERROR,
 5         SW_INTEGER,
 6         SW_INTEGER_START,
 7         SW_SIMPLE,
 8         SW_BULK,
 9         SW_BULK_LF,
10         SW_BULK_ARG,
11         SW_BULK_ARG_LF,
12         SW_MULTIBULK,
13         SW_MULTIBULK_NARG_LF,
14         SW_MULTIBULK_ARGN_LEN,
15         SW_MULTIBULK_ARGN_LEN_LF,
16         SW_MULTIBULK_ARGN,
17         SW_MULTIBULK_ARGN_LF,
18         SW_RUNTO_CRLF,
19         SW_ALMOST_DONE,
20         SW_SENTINEL
21     } state;

redis回复包状态转化图

在这幅redis回复包状态转化图中,每个状态下面的条件,就是进入该状态的条件,通过这些,我们可以解析回复包。如:

*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n

总结

在上述章节中,我们了解了redis的协议,以及twemproxy对redis请求包和回复包的解析过程,利用有限状态机的模型来去熟悉解析过程,下面我们会探索msg_resv的过程。

另外,对于博文有问题的请大家在评论中留言与博主讨论,博主会及时回复的!!!!

时间: 2024-10-21 17:19:53

twemproxyRedis协议解析探索——剖析twemproxy代码正编的相关文章

twemproxyMemcache协议解析探索——剖析twemproxy代码正编补充

memcache是一种和redis类似的高速缓存服务器,但是memcache只提供键值对这种简单的存储方式,相对于redis支持的存储方式多样化,memcache就比较简单了.memcache通过tcp或者udp连接来实现memcache客户端和服务端的交互.memcache的协议是自定的,也分为两种:一种是文本协议(这是我们今天讨论的重点),另一种是二进制协议(在我们今天讨论的范围),这里仅仅介绍用tcp连接以及文本协议通信的memcache协议.如有描述不当的地方请大家指出. memcach

twemproxy发送流程探索——剖析twemproxy代码正编

本文想要完成对twemproxy发送流程--msg_send的探索,对于twemproxy发送流程的数据结构已经在<twemproxy接收流程探索--剖析twemproxy代码正编>介绍过了,msg_send和msg_recv的流程大致类似.请在阅读代码时,查看注释,英文注释是作者对它的代码的注解,中文注释是我自己的感悟. 函数msg_send 1 rstatus_t 2 msg_send(struct context *ctx, struct conn *conn) 3 { 4 rstatu

通用轻量级二进制格式协议解析器

在通信协议中,经常碰到使用私有协议的场景,报文内容是肉眼无法直接看明白的二进制格式.由于协议的私有性质,即使大名鼎鼎的 Wireshark,要解析其内容,也无能为力. 面对这种情况,开发人员通常有两个办法:第一,对照报文内容和协议规范进行人工分析(假设内容没有经过加密.压缩):第二,编程实现协议报文的解析(源于程序员的懒惰 ^_^). 很明显,第二条道路是主流.目前比较常见的实现方式是开发对应的 Wireshark 插件,包括 C.Lua 等插件.当然,插件完成后需要运行 Wireshark 才

协议解析Bug分析

协议解析Bug分析 源自邮件协议RPC(远程过程调用)处理的Request请求数据包的bug.        一.Bug描述 腾讯收购的Foxmail客户端可以作为outlook客户端的替代品与Exchange服务端进行交互完成邮件收发.而我们所要做的就是让邮件经过我们代理的优化处理. 这时候问题来了,Outlook客户端经由我们代理没有任何问题:但是换成Foxmail就会有错误弹窗,错误号:0x000006BE.但是如果不经过代理,Foxmail收发邮件一切正常. 很明显,是代理出了问题.  

视音频数据处理入门:UDP-RTP协议解析

===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理入门:PCM音频采样数据处理 视音频数据处理入门:H.264视频码流解析 视音频数据处理入门:AAC音频码流解析 视音频数据处理入门:FLV封装格式解析 视音频数据处理入门:UDP-RTP协议解析 ===================================================

i2c知识总结及协议解析

知识总结部分: 一. 技术性能: 工作速率有100K和400K两种: 支持多机通讯: 支持多主控模块,但同一时刻只允许有一个主控: 由数据线SDA和时钟SCL构成的串行总线: 每个电路和模块都有唯一的地址: 每个器件可以使用独立电源 二. 基本工作原理: 以启动信号START来掌管总线,以停止信号STOP来释放总线: 每次通讯以START开始,以STOP结束: 启动信号START后紧接着发送一个地址字节,其中7位为被控器件的地址码,一位为读/写控制位R/W,R. /W位为0表示由主控向被控器件写

CJ/T-188 冷热量表协议解析2

本文具体阐述JY公司冷热量表(记热量)传输协议,并以此说明CJ/T-188协议在厂家具体应用时,并不一致.本文及后续文章将对这些不同点予以总结(文中所述协议与日志"CJ/T-188 冷热量表协议解析1"http://user.qzone.qq.com/2756567163/blog/1437462157的不同之处,将用红色予以标识).以下数据未经特殊说明,均指十六进制. 数据发送: FE FE FE FE 68 20 32 41 31 40 00 00 00 01 03 90 1F 0

经常使用传感器协议3:CJ/T-188 冷热量表协议解析2

????本文详细阐述JY公司冷热量表(记热量)传输协议.并以此说明CJ/T-188协议在厂家详细应用时,并不一致. 本文及兴许文章将对这些不同点予以总结(文中所述协议与日志"CJ/T-188 冷热量表协议解析1"http://user.qzone.qq.com/2756567163/blog/1437462157的不同之处,将用红色予以标识).下面数据未经特殊说明.均指十六进制. ????数据发送: ????????FE FE FE FE?68 20 32 41 31 40 00 00

AOSP中的HLS协议解析

[时间:2018-04] [状态:Open] [关键词:流媒体,stream,HLS, AOSP, 源码分析,HttpLiveSource, LiveSession,PlaylistFetcher] 1. 引言 本文作为HLS综述的后续文章,也是我之前对Nuplayer源码分析中GenericSource源码解析的姊妹篇.当然本文侧重于结合HLS原理来分析NuPlayer中相关实现逻辑.如果你对NuPlayer不是很了解,建议先简单了解下. 本文重点关注的是NuPlayer中的HttpLiveS