twemproxyMemcache协议解析探索——剖析twemproxy代码正编补充
memcache是一种和redis类似的高速缓存服务器,但是memcache只提供键值对这种简单的存储方式,相对于redis支持的存储方式多样化,memcache就比较简单了。memcache通过tcp或者udp连接来实现memcache客户端和服务端的交互。memcache的协议是自定的,也分为两种:一种是文本协议(这是我们今天讨论的重点),另一种是二进制协议(在我们今天讨论的范围),这里仅仅介绍用tcp连接以及文本协议通信的memcache协议。如有描述不当的地方请大家指出。
memcache文本协议
存储命令
add/replace/set/append/prepend命令格式如下:
<command name> <key> <flags> <exptime> <bytes>\r\n
<data block>\r\n
格式的介绍如下:
<command name>可以是add(即增加不存在的键值对),replace(即替换存在的键值对),set(上述两种的功能都具有),append(在存在的键对应的值后增加对应的内容)以及prepend(在存在的键对应的值之前增加对应的内容)。
<key> 是数据项的键名。
<flags>是在取回内容时,与数据和发送块一同保存服务器上的任意16位无符号整形(用十进制来书写),一般为0。
<exptime> 是有效时间。如果为0,该项永不过期,如果非0,该项将在<exptime> 后删除。
<bytes>是<data block>的长度,是数据项的长度。
<data block>是数据项的数据。
add/replace/set/append/prepend命令回复
"STORED\r\n"表明存储成功。
"NOT_STORED\r\n"表明数据没有被存储,但不是因为发生错误。这通常意味着add , replace的条件不满足或者项目已经位列删除队列(参考后文的“delete”命令)。
cas命令格式如下:
cas <key> <flags> <exptime> <bytes> <cas unique> [noreply]\r\n
<data block>\r\n
<key> ,<flags>,<exptime>, <bytes>以及<data block>同add/replace/set/append/prepend命令
<cas unique> 是一个与已存数据条目相关的全局唯一的64位数。客户端应该使用"gets"命令返回的该值来进行"cas"更新操作。
[noreply]是可选项指示不要回复。注意:如果请求行格式错误,服务器不一定能可靠地解析"noreply"选项。在此种情况下,它可能会发送错误信息给客户端,如果客户端没有读取该信息的话会带来问题。客户端应该只构造合法的请求。
cas命令回复如下:
"EXIST\r\n" 指示要更新的数据自你上次取过后已经过修改。
"NO_FOUND\r\n" 指示要修改的数据并不存在。
delete格式命令如下:
delete <key> <time>\r\n
delete是删除对应的键名。
<key> 是需要删除的键名。
<time>是一个单位为秒的时间,在该时间内服务器会拒绝对于此键名的“add”和“replace”命令。此时内容被放入delete队列,无法再通过“get”得到该内容,也无法是用“add”和“replace”命令(但是“set”命令可用)。直到指定时间,这些内容被最终从服务器的内存中彻底清除。
delete命令回复如下:
"DELETED\r\n"表示执行成功
"NOT_FOUND\r\n"表示没有找到这项内容
读取命令
get/gets命令格式如下:
get/gets <key>*\r\n
<key>*指的是多个以空格分割的键名。
get/gets命令回复如下:
VALUE <key> <flags> <bytes> [<cas unique>]\r\n
<data block>\r\n
<key>是数据项的键名
<flags>是由存储命令设置的flags,一般为0
<bytes>是数据块的长度
<cas unique>是一个64位整数,唯一标识了一个特定的数据项。
<data block>是数据项的数据。
这里的所有数据以"END"结束。
incr/desc命令格式如下:
incr/desc <key> <value> [noreply]\r\n
<key>是数据项的键名
<value>是对数据项incr(递增)/desc(递减)的值。它是一个64位的无符号十进制整数。
[norply]是可选参数,不要回复。
incr/desc命令回复:
"NOT_FOUND\r\n" 指示这个数据项找不到。
"<value>\r\n", 其中<value>是这个数据项在经过递增/递减操作后的新值。
memcache文本协议的请求的解析
这个是在proto/memcache.c里的memcache_parse_req函数
它也是用有限状态机去完成解析的
enum {
SW_START,
SW_REQ_TYPE,
SW_SPACES_BEFORE_KEY,
SW_KEY,
SW_SPACES_BEFORE_KEYS,
SW_SPACES_BEFORE_FLAGS,
SW_FLAGS,
SW_SPACES_BEFORE_EXPIRY,
SW_EXPIRY,
SW_SPACES_BEFORE_VLEN,
SW_VLEN,
SW_SPACES_BEFORE_CAS,
SW_CAS,
SW_RUNTO_VAL,
SW_VAL,
SW_SPACES_BEFORE_NUM,
SW_NUM,
SW_RUNTO_CRLF,
SW_CRLF,
SW_NOREPLY,
SW_AFTER_NOREPLY,
SW_ALMOST_DONE,
SW_SENTINEL
} state;
这里的有限状态机图如下:

storage就是存储命令,即add/replace/set/append/prepend/cas命令,retreval就是读取命令,即get\gets命令,other就是除了存储命令,get\gets命令,touch命令,incr/desc命令之外的命令。
例如get\gets命令,先是SW_REQ_TYPE,就是get\gets字符串,再是SW_SPACES_BEFORE_KEY,即空格,然后使SW_KEY,就是键名,接着回到SW_SPACES_BEFORE_KEY,不断往复。
memcache文本协议的回复的解析
这个是在proto/memcache.c里的memcache_parse_rsp函数
它也是用有限状态机去完成解析的,下面是这些状态。
enum {
SW_START,
SW_RSP_NUM,
SW_RSP_STR,
SW_SPACES_BEFORE_KEY,
SW_KEY,
SW_SPACES_BEFORE_FLAGS, /* 5 */
SW_FLAGS,
SW_SPACES_BEFORE_VLEN,
SW_VLEN,
SW_RUNTO_VAL,
SW_VAL, /* 10 */
SW_VAL_LF,
SW_END,
SW_RUNTO_CRLF,
SW_CRLF,
SW_ALMOST_DONE, /* 15 */
SW_SENTINEL
} state;
这里的有限状态机图如下:

例如,如果是get和gets的回复就会先进入SW_RSP_STR,即“VALUE”,接着进入SW_SPACES_BEFOER_KEY这条线,知道这行的结束SW_RUNTO_CRLF,然后进入数据块SW_RUNTO_VAL这条线,知道SW_RSP_STR,直至到SW_RSP_STR中解析出“END”,会到SW_CRLF这条线。
总结
本文主要介绍了memcache的文本协议以及tweproxy如何解析memcache请求包和memcache回复包。
twemproxyMemcache协议解析探索——剖析twemproxy代码正编补充的更多相关文章
- twemproxyRedis协议解析探索——剖析twemproxy代码正编
这篇文章会对twemproxyRedis协议解析代码部分进行一番简单的分析,同时给出twemproxy目前支持的所有Redis命令.在这篇文章开始前,我想大家去简单地理解一下有限状态机,当然不理解也是 ...
- twemproxy发送流程探索——剖析twemproxy代码正编
本文想要完成对twemproxy发送流程--msg_send的探索,对于twemproxy发送流程的数据结构已经在<twemproxy接收流程探索--剖析twemproxy代码正编>介绍过 ...
- twemproxy接收流程探索——剖析twemproxy代码正编
本文旨在帮助大家探索出twemproxy接收流程的代码逻辑框架,有些具体的实现需要我们在未来抽空去探索或者大家自行探索.在这篇文章开始前,大家要做好一个小小的心理准备,由于twemproxy代码是一份 ...
- twemproxy代理主干流程——剖析twemproxy代码正编
在twemproxy的发送和接收流程剖析中,我们已经完全弄清楚twemproxy如何将客户端以及服务端发来的包切分成msg,获得一个独立的msg后twemproxy应该如何处理?这是本文这次需要重点介 ...
- twemproxy分片处理原理--剖析twemproxy代码正编
twemproxy在redis上能处理多命令流程只有mset,mget,del的命令,例如mset的话是mset k1 v1 k2 v2 k3 k3,mget的话是mget k1 k2 k3,del的 ...
- twemproxy代码框架概述——剖析twemproxy代码前编
本篇将去探索twemproxy源码的主干流程,想来对于想要开始啃这份优秀源码生肉的童鞋会有不小的帮助.这里我们首先要找到 twemproxy正确的打开方式--twemproxy的文件结构,接着介绍tw ...
- twemproxy架构分析——剖析twemproxy代码前编
twemproxy背景 在业务量剧增的今天,单台高速缓存服务器已经无法满足业务的需求, 而相较于大容量SSD数据存储方案,缓存具备速度和成本优势,但也存在数据安全性的挑战.为此搭建一个高速缓存服务器集 ...
- twemproxy接收流程探索——twemproxy代码分析正编
在这篇文章开始前,大家要做好一个小小的心理准备,由于twemproxy代码是一份优秀的c语言,为此,在twemproxy的代码中会大篇幅使用c指针.但是不论是普通类型的指针还是函数指针,都可以让我们这 ...
- 剖析twemproxy前言
又是喜闻乐见的新坑,前面的mysql协议,当我在解读go-mysql包的时候,会重新讲到,至于Leetcode的更新会与go语言同步.关于这个redis的新坑,目前打算通过剖析twemproxy源码来 ...
随机推荐
- cocoapods安装和使用常见问题及解决方案
cocopods安装后pod install出现以下错误 /usr/local/Cellar/ruby/2.4.1_1/lib/ruby/2.4.0/rubygems.rb:270:in find_s ...
- springboot 1.5.2 集成kafka 简单例子
添加依赖 compile("org.springframework.kafka:spring-kafka:1.1.2.RELEASE") 添加application.propert ...
- mysql之 日志体系(错误日志、查询日志、二进制日志、事务日志、中继日志)
一. mysql错误日志:错误日志记录的事件:a).服务器启动关闭过程中的信息b).服务器运行过程中的错误信息c).事件调试器运行一个事件时间生的信息d).在从服务器上启动从服务器进程时产生的信息lo ...
- Sql的连接表补充
连接条件可在FROM或WHERE子句中指定,建议在FROM子句中指定连接条件.WHERE和HAVING子句也可以包含搜索条件,以进一步筛选连接条件所选的行. 连接可分为 ...
- 抽象工厂(AbstractFactory)模式-创建型模式
1.new 的问题 常见的对象创建方法: //创建一个Road对象 Road road=new Road(); new的问题:实现依赖,不能应对具体实例的变化 怎么理解上面这句话呢? 可以这样理解:我 ...
- canvas实现视频截图
截取视频当前播放画面,直接上源码. <body> <div class="container"> <video id="test" ...
- NodeMCU入门(4):搭建Web服务器,配置网络连接
准备工作 1.NodeMCU模块 2.ESPlorer v0.2.0-rc6 3.NodeMCU-HTTP-Server 搭建web服务器 下载https://github.com/wangzexi/ ...
- 《Python编程从入门到实践》_第四章_操作列表
for循环遍历整个列表 pizzas = ['pizzahut','dicos','KFC'] for pizza in pizzas: print ("I like "+ piz ...
- JDBC加载数据库驱动的方式
JDBC作为数据库访问的规范接口,其中只是定义一些接口.具体的实现是由各个数据库厂商来完成. 一.重要的接口: 1.public interface Driver 每个驱动程序类必须实现的接口.Jav ...
- 美丽的CSS图形和HTML5
1.HTML5基础 文档类型 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "htt ...