分类: C/C++
2014-05-05 15:51:15
原文地址:Memcached内部协议解析(ascii_prot) 作者:CUKdd
Memcached的客户端和服务器之间通过TCP连接进行通信。(UDP方式也是可以的,详细信息见本文最后的"UDP protocol"解析)。运行中的memcached服务器监听在一些(可配置的)端口上;客户端通过连接到该端口,可以向服务器发送命令,读取应答,最后在关闭连接。
Memcached服务器不必发送任何命令来结束会话,这个工作仅仅由客户端来执行,当它不再需要该连接的时候。注意,尽管如此,我们也是鼓励客户端软件缓存他们的连接的,而不建议对每一次的数据存、取都重新开启一个新的连接。这是因为memcached是专门为高效地处理大量(数百个,甚至在需要的时候会达到上千个)的并发连接而设计的。缓存连接将会消除建立TCP连接相关的开销(与服务器端准备一个新的连接时的开销相比,这是微不足道的)。
在memcache协议中有两种方式可以传送数据:文本行(text lines)和非结构化数据(unstructured data)。text lines用于在客户端和服务器之间传送命令(commands)和响应(responses)数据。Unstructured data将会被发送,当客户端想要存储或是索取数据的时候。服务器将向客户端传回和它从客户端收到的完全相同格式的非结构化数据(unstructured data),并且一字节流的方式传送。服务器并不关心unstructured data的字节序问题,并且也意识不到它们。对unstructured data中可以出现的字符种类没有任何限制;然而,对于读取该数据的一端(或者是客户端或者是服务器)将通过前面处理的文本行总是能知道待提交或接收的数据块的精确长度。
Text lines总是以"\r\n"作为数据块结束符号的。Unstructured data也以"\r\n"作为数据块结束符,即使在数据中出现了'\r'、'\n'或是其他的任何8-bit字符,同样也以它作为结束符。因此,当客户端从服务器索要数据时,它必须使用数据块的长度来定位数据块的结束位置,而不能依靠数据块后面跟随的'\r\n'。即使它确实是这么做了。
1. 键(keys)
存储在memcached中的数据是借助key的帮助而加以区分的。键(key)是一个文本串,它将用来唯一的确定客户端想要存储和索取的数据。目前,key的长度限制在250个字符之内(当然,正常来讲,客户端是不需要这么长的key的);key中是不允许包含控制字符或是空白(e.g. '\t'、'\n'、' ')字符的。
2. 命令(commands)
有三种类型的命令:存储命令、检索命令、其他命令(它们不涉及unstructured data)。
存储命令有六个:"set","add","replace","append","prepend","cas"。它们用来告诉服务器存储一些用key唯一标识的数据。客户端首先发送一个命令行,然后是一个数据块;之后客户端即可等待服务器的响应数据,用于查看操作成功(success)还是失败(failure)。
检索命令有两个:"get"和"gets"。它们要求服务器检索与一些key(在一个request中,可以有一个或多个key)相关联的数据。客户端发送一个包含一个或多个key的命令行到服务器,然后服务器把查找到的每一个项目(item),作为一个响应行发送到客户端;其中包含了该项目(item)的一些信息,而后是该项目的数据块内容;这种过程一直持续到服务器向客户端发送了一个"END"的响应时为止。
对于其他所有的命令,它们都不涉及到unstructured data。客户端发送一个命令行,然后等待(依赖于命令)一个或是多个响应(以最后一行的"END"作为结束)。
一个命令行总是以这个命令的名字作为开始,后面跟着一系列由空格分割的参数列表。命令的名字是小写的,并且是大小写敏感的。
3. 到期时间(Expiration times)
一些命令会涉及到客户端发送到服务器的各种到期时间(相对于一个项目-itme-或是一种操作)。在这种情况下,到期时间的实际值或者是Unix时间(Unix time)(一个32位数,起始于1970年1月1号的秒数)或者起始于现在的秒数。在后面的一种情况中,这个数字不能超过60*60*24*30(一个月(30天)内的秒数)。如果客户端发送的到期时间超过了这个数值的话,那么服务器将认为它是Unix时间,而不是起始于现在的时间。
4. 错误描述字符串(Error strings)
服务器对客户端发送过来的每一个命令可能会回应一个错误描述字符串。错误描述字符串有一下三种类型:
在下面对个别命令的详细描述过程中,将不再对错误输出行进行详细的解释,但是客户端必须有允许它们的可能性。
5. 存储命令(storage commands)
首先,客户端发送的命令行应该具有如下格式:
cas
跟随在上面一行数据之后的将是下面的数据块:
在发送了以上命令和数据块之后,客户端将等待如下格式的应答数据:
6. 检索命令(Retrieval command)
检索命令"get"和"gets"操作格式如下:
get
gets
该命令意味着客户端希望接受0个或是多个items,每一个item将作为文本行格式接受,并且后跟一个数据块。当所有items都传送完毕后,服务器将单独发送一个
"END\r\n"
作为响应的结束。
从服务器响应的每一个item,其格式如下所示:
VALUE
\r\n
如果客户端检索请求中的一些keys没有被服务器传回的话,那么说明没有存储与这些key相关联的item(因为他们可能从来没被存储或是存储了但是在为其他的items准备空间时而被删除了或是超时了或者是被一个客户端确定地删除了)。
7. 删除命令(Deletion)
"deletion"允许明确地删除一些items,格式如下:
delete
服务器对此命令的应答行具有如下形式:
若想了解如何立刻使已经存在的所有项目失效,请看"flush_all"命令。
8. 递增(Increment)/递减(Decrement)操作
"incr"和"decr"命令用于就地改变一些item的数据(data),增减或减少它们。这个item的数据(data)是一个十进制表示的64-bit无符号整数。如果当前数据不符合这种表示,那么incr/decr命令将返回一个错误(如果它是0,memcached <= 1.2.6把它作为虚假值来处理)。另外,incr/decr命令要能成功的工作,那么他们所操作的item必须已经存在。这些命令不会把不存在的key当作存在的0来处理;相反,他们将宣告失败。
命令格式如下,他们由客户端发送:
incr
or
decr
服务器将对该命令回复如下的数据:
注意,当客户端试图减小该数值到0一下的时候,decr命令将发生下溢出,此时这个新value值将是0。在incr命令中发生上溢时,将用64-bit的掩码将其调整到合法的数据范围之内。
另外,还要注意当增加一个数值而导致长度丢失的时候,将不能保证增加它返回的长度。这个数值可能在最后填充空白,但这纯粹是实施优化,所以你不你能依赖于它。
9. 统计命令(statistics)
"stats"命令用于向服务器请求有关它维护的和系统内部其他的数据。其格式有两种形式:无参数和有参数的。
无参数格式:
stats\r\n
它将导致服务器会传一般目的的统计信息和设置,具体件下文。
有参数格式:
stats
依赖于这些参数
10. 通用目的的状态统计
依据接收到的无参数的"stats"命令,服务器将会回传数行如下格式的数据:
STAT
服务器将以 END\r\n 作为数据传送结束标志。
在每一行的统计信息中,
图列表 暂略
11. 设置统计信息(Setting statistics)
这节所描述的统计信息,将来有可能会发生变化,请以源码包中的protocol.txt中的为准。
带有参数的"stats"设置命令,将会返回设置的详细信息。
暂略。
12. 项目统计命令(Item statistics)
这节所描述的统计信息,将来有可能会发生变化,请以源码包中的protocol.txt中的为准。
带有参数"item"的"stats"命令,将返回每个slab class中item的容量信息。数据的格式如下:
STAT item:
服务器将以 END\r\n 结束上述数据的传送。
下面的不知该如何解读,特附原文如下:
The slabclass aligns with class ids used by the "stats slabs" command. Where "stats slabs" describes size and memory usage, "stats items" shows higher level information.
13. 其他命令(Other commands)
"flush_all"是一个可选的数字参数的命令。它总是执行成功,并且服务器会返回一个"OK\r\n"作为应答(除非提供了最后一个参数"noreply")。它的作用是立即使已经存在的所有items失效(默认方式),或者是在一定的超时时间之后失效。项目失效之后,服务器将不会为客户端的检索命令(除非又在原来失效的键值的地方存放了新的数据)返回任何数据。flush_all命令实际上并不会释放被已经存在的items占用的内存空间。对flush_all命令最确切的定义如下:
It causes all items whose update time is earlier than the time at which flush_all was set to be executed to ignored for retrieval purposes.
为"flush_all"命令设置延时的目的是在你有一个memcached服务器池,并且你需要刷新所有内容,那么这就允许你可以不再同一时刻(这样的话,可能会导致一个所有客户端突然需要重新创建内容(或许这些内容在memcached守护进程中也能被找到)而使数据库出现一个负载高峰)重置所有memcached服务器的选项。
延迟选项允许你在重置项目时可以有一定的时间间隔,比如10秒(可以通过第一次传递一个0,第二次传递一个10,第三次传递一个20,等等来实现)。
"version"是一个无参命令,格式如下:
version\r\n
服务器对其的回应格式如下:
"VERSION
"verbosity"是一个带有数字化参数的命令。它总是执行成功,并且服务器通过发送"OK\r\n"作为应答(除非"noreply"作为最后一个参数被提供)。它的作用就是用来设置输出日志的等级水平的。
"quit"也是一个无参数的命令,格式如下:
quit\r\n
当收到该命令时,服务器将关闭连接。但是,当一个连接不再需要的时候,客户端会简单的将其关闭,而不会发送任何命令。
14. UDP协议(UDP protocol)
对于安装了足够多数量的客户端,并且会产生超大量的TCP连接的环境,memcached就会出现扩展困难的问题,所以这里也提供了一种基于UDP的接口。UDP接口不保证成功交付,因此因该被使用于不要求成功的操作中;通常把一个丢失了的或是不完整响应的"get"命令当作缓存不命中来对待。
每一个UDP数据报包含一个简单的桢头,后面跟随着格式如同上面对TCP协议描述时相同的数据。在当前的实现中,请求必须被包含在一个简单的UDP数据报中,但是响应可以分散在多个数据报中。(唯一相同的是包含多个键值的"get"和"set"命令的跨越多个数据报文的请求,无论如何,它们都是适合使用TCP可靠传输的原因)
桢头长8个字节,如下(所有值都是16-bits的网络序整数,高字节优先):
0-1 请求ID
2-3 序列号
4-5 在这个消息中的数据报总数
6-7 留作以后使用,值必须是0
请求ID是由客户端提供的。通常它从一个随机的种子数值开始单调递增,但是客户端可以随意使用它喜欢的任何数值作为请求ID。服务器的响应将会包含与收到的请求中的相同的ID。当有来自同一个服务器的多个悬而未决的数据报时,客户端可以使用该请求ID去区分响应和请求;任何带有不可识别请求ID的数据报将都可能是对早些时候请求的延迟响应,那么此时应该将其丢弃。
序列号的范围是从0到n-1,这里的n是该消息中的数据报总数。客户端需要使用序列号将响应中的数据报负载串联起来;重组后得到的数据和使用TCP传输来的数据具有相同的格式(包括结束序列\r\n)。
<完整版 - 结束>