[翻译]memcached 文本协议(未完成)

来源:互联网 发布:学数据库之前学什么 编辑:程序博客网 时间:2024/06/16 06:32

协议
________
memcached客户端通过tcp连接与服务端通信。
(同时也提供了1个UDP接口;更多细节在后面的"UDP协议"一节详述)
memcached服务端侦听某个特定端口,客户端连接到该端口,发送命令给服务端,读取响应内容,最后关闭连接。

双方无须发送任何命令结束会话。一个客户端可以随时关闭连接。但是,建议客户端缓存连接,以免每一次存取数据都重新打开连接。因为memcached做了特别的设计,即使大量连接的情况下,也能够高效运行。缓存连接可以避免建立TCP连接的消耗(与此对比,在服务端准备一个新连接的消耗就微不足道了)。

memcache协议发送包含两种数据:文本行和非结构化数据(unstructured data)。 文本行用于客户端发送命令,以及服务端返回内容。非结构化数据,是在客户端存取数据时使用。服务端会把非结构化数据以字节流形式返回。服务端处理非结构数据是不关心也不会意识到字节顺序的问题。非结构化数据并没有禁止字符串出现,但是读取方可以从首先读取到的文本行得到正在传输的数据块(data block)的精确长度。

文本行通常以\r\n结尾。非结构化数据也是以\r\n结尾。但是,数据里可能出现\r,\n或者其他8- bit字符串。
因此,当客户端接收到服务端返回数据时,必须使用数据块(data block)长度判断数据块的结尾,而不是根据数据块最后的\r\n。

Keys
----
memcached依靠key识别所存的数据。key是一个文本字符串,客户端存取操作使用key来唯一识别数据。目前key的长度限制为250字符。key不能包含控制字符和空格。

Commands
--------
命令分为3种类型。

存储命令(6种:set/add/replace/append/prepend/cas)
要求服务端存储以key识别的数据。客户端发送一个命令行,然后是数据块;然后,客户端希望获得一行返回内容,表明成功还是失败。

获取命令(2种:get/gets)
要求服务端返回key集合(一个请求可以是1个或多个key)对应的数据。客户端发送一个命令行,包含所有要请求的key;然后,服务器每找到一项key对应的数据,就返回一行响应(携带了相关信息),以及一个包含数据的数据块;最后服务端返回以"END"命令行结束。

其他所有命令不涉及非结构化数据(unstructured data)。客户端发送一个命令行,并希望服务端返回一行或多行响应并在最后一行以“END”结束。

一个命令行总是以命令名开头,紧跟着以空格分隔的参数。命令名必须小写,并且大小写敏感。

过期时间
----------------
客户端发送给服务端一些命令可以带过期时间。在这些情况下,发送的值可以是Unix时间(自1970年1月1日起的秒数),或者是距目前时间的秒数。在后一种情况下,秒数不能超过60*60*24*30(30天);如果大于此值,服务端会当作真实的Unix时间而不是距今的秒数。

Error字符串
-------------
客户端发送的每一个命令可能收到服务端包含error字符串的应答。这些error字符串有3中形式:

-"ERROR\r\n"
表示客户端发送了一个不存在的命令名字

- "CLIENT_ERROR <error>\r\n"
表示客户端输入的命令行有某种错误。例如,输入没有遵循协议。<error>是一个容易理解的error字符串。

-"SERVER_ERROR <error>\r\n"
表示服务端某种错误阻止其继续执行命令。<error>是一个容易理解的error字符串。在严重的服务器错误发生时,不能继续应答客户端(这种情况应该很少发生),服务端在发送error行后将关闭连接。这是服务端主动关闭与客户端连接的唯一一种情况。

下面对每一个命令的描述中,这些error行不再特别提到,但是客户端要兼容它们出现的可能性。

存储命令(Storage commands)

----------------

首先,客户端发送一个命令行,如下:
<command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
cas <key> <flags> <exptime> <bytes> <cas unique> [noreply]\r\n

<command name> 是指 "set", "add", "replace", "append" or "prepend"
"set"表示“存储这项数据”

"add"表示“仅当服务端没有这个key对应的数据时,存储这项数据”


"replace"表示“仅当服务端有这个key对应的数据时,存储这项数据”

“append”表示“在现有key对应数据后添加该项数据”

“prepend”表示“在现有key对应数据前添加该项数据”

"cas" 是一个检测和设值的操作,表示“仅当自上一次获取后没人修改过,才存储这项数据”

- <key> 客户端所要求存储数据的key


- <flags>是一个任意16位非负整数(以decimal的形式显示),服务端会将其和数据一起存储,并且在数据被获取时跟随返回给客户端。客户端可以把它作为一个位字段,用来存储数据特定信息。服务端是看不懂这个字段的含义的。需要说明,memcached 1.2.1 及更高版本,flags可能为32位,而不是16位。但是你可能希望限制为16位,以兼容旧版本。


- <exptime> 表示过期时间。如果是0,数据不会过期(但是它可能被删除,以便为其他数据留出空间)。如果是非0值(Unix时间或者距今的秒数偏移值),当过了这个过期时间,客户端必定不能获取到该数据(以服务器时间为衡量标准)。

- <bytes> 是指数据块部分的字节数,不包括\r\n分隔符长度。<bytes>可能为0(数据块为空)

- <cas unique> 表示现有数据项的一个独一无二的64位值。客户端想发起cas更新时,应该线程从gets命令获得该值。

- "noreply" 为可选参数,告诉服务端不用回复。说明:如果请求行格式错误,服务端不能正确识别noreply选项。在这种情况下,服务端发送错误给客户端,如果客户端没有读取错误信息,将使工作无法继续(翻译不妥,什么意思?)。所以,客户端应该构造有效的请求。

命令行之后,客户端将发送数据块:

<data block>\r\n


- <data block>是一组由任意8-bit数据组成的,总长度与命令行的<bytes>参数一致的数据块。

发送完命令行及数据块,客户端等待回复,可能是以下形式:

- "STORED\r\n",表示成功

- "NOT_STORED\r\n" 表示数据未保存成功,但是不是因为发生错误。通常是因为"add"或者"replace"命令所需条件不满足。

-"EXISTS\r\n" 表示你想用"cas"指令存储的数据项,自从你上次获取后,现在已经被修改。

-"NOT_FOUND\r\n" 表示你想用"cas"指令存储的数据项不存在。


获取命令(Retrieval Command)
-----------------------
获取命令"get"和"gets"的操作如下:

get <key>*\r\n
gets <key>*\r\n

- <key>* 表示一个或多个以空格分隔的key字符串

发送此命令后,客户端期望0个或多个数据项返回,这些数据项应该存在于文本行后面的data block区域。在所有数据项传输完毕后,服务端发送字符串:
"END\r\n"
表示响应结束。

服务端发送的数据项格式如下:
VALUE <key> <flags> <bytes> [<cas unique>]\r\n
<data block>\r\n

- <key>是数据项的key
- <flags> 是存储命令设置的flags的值
- <bytes>是紧随其后的data block的数据长度,不包括分隔符\r\n

- <cas unique> 是一个64位唯一整数,能唯一标示数据项
- <data block> 是该数据项的数据内容

如果没有在响应里找到某些keys对应的数据项,意味着服务端没有key对应的数据(或许因为一直都没存储过,或许存储过,但是被删掉为其他数据腾出空间,又或许是数据已经过期,又或许是被客户端删掉)。


删除命令(Deletion)
-------------------

"delete"命令允许对数据项进行删除:

delete <key> [noreply]\r\n


- <key> 客户端希望服务端删除的数据对应的key


- "noreply" 是一个可选参数,表示服务端无须发送回复。详见存储命令关于不规范的请求格式一节。

该命令响应行,可能为下面其中一个:

- "DELETED\r\n" 表示删除成功
- "NOT_FOUND\r\n" 表示key对应的数据项不存在

要想所有现存数据失效,详见下面提到的"flush_all"命令


增减命令(Icrement/Decrement)
---------------------
"incr" 和"decr"命令,可以修改指定数据值,使其增加或者减少。数据值被当作是一个64位无符号的十进制整数。如果当前值不符合上述十进制表示法,incr/decr命令将返回一个错误(memcached<=1.2.6则把错误值看做是0,这带来了一点混乱。)另外,数据项必须存在,才能使incr/decr继续执行。这两个命令不会捏造一个不存在的数据的值为0,相反,它们会认为此次操作是失败的。

客户端发送的命令如下:
incr <key> <value> [noreply]\r\n 
或者
decr <key> <value> [noreply]\r\n 
- <key> 是客户端期望改变的数据项对应的键
- <value> 是客户端期望给数据项增加的值的大小。它是一个64位无符号的十进制整数。

- "noreply" 是可选参数,告诉服务端不用回复 。详见存储命令关于不规范的请求格式一节。

响应的格式将包括以下形式:
- "NOT_FOUND\r\n" 表示key对应的数据项不存在

- <value>\r\n 是执行此次incr/desc命令后,数据项最新的值

要注意的是,"decr"命令里的-号会做特殊处理:如果客户端尝试给某数据减去一个小于0的值,那么该数据项的值将变为0。(而事实上,旧版本的memcached才会设为0,新版本的memcached会报错"CLIENT_ERROR invalid numeric delta argument")。"incr"命令会自动避免溢出(0 - 2^64-1)。

(欠一段翻译,未看懂

Note also that decrementing a number such that it loses length isn't
guaranteed to decrement its returned length. The number MAY be
space-padded at the end, but this is purely an implementation
optimization, so you also shouldn't rely on that.)

Touch命令
--------
"touch"命令的作用是更新一个已有数据项的过期时间,却不用获取它。

touch <key> <exptime> [noreply]\r\n

- <key> 表示客户端期望删除的数据项对应的key(此处原文貌似有误,不是删除的数据项,应该是更新的数据项)

- <exptime> 是过期时间。与更新命令(set/add等)里所定义的含义相同。它会替换已有的过期时间。如果一个已有数据项将在10s内过期,但是被一个touch命令更新过期时间为"20",数据项将在之后20秒过期失效。

- "noreply" 是可选参数,告诉服务端不用回复 。详见存储命令关于不规范的请求格式一节。

该命令响应行,可能为下面其中一个:

- "TOUCHED\r\n" 表示更新成功

- "NOT_FOUND\r\n" 表示key对应的数据项不存在

Slabs 重分配(Slabs Reassign)
--------------------
说明:该命令截至这份文档编写时可能会有所变更。
slabs重分配命令的作用是,在一个实例达到其使用的内存上限时,进行内存重新分布 。这个动作会使内存的分布情况与服务刚启动时自动分布的内存情况不同。


slabs reassign <source class> <dest class>\r\n

- <source class> 是要偷取的page所属slab class的id。
如果souce class id为-1,表示选择任意一个有效的class。

- <dest class> 是把page移动的目标slab class的id。

[译者注, 需要开启slabs assign功能: memcached -o slab_reassign ,否则会出现错误提示:“CLIENT_ERROR slab reassignment disabled”]
该命令返回的响应行将包括以下形式: 
- "OK" 表示该page已将按计划进行移动
- "BUSY [message]" 表示正在处理某一page,迟些再试
- "BADCLASS [message]" 指定了一个无效的class id
- "NOSPARE [message]" source class没有空闲的page
- "NOTFULL [message]" dest class 必须填满,以便放入新page- "UNSAFE [message]" source class 现在不能移动一个page
- "SAME [message]" 必须指定不同的source/dest id

Slabs自动移动 [ Slabs Automove ]
-----------------
说明:该命令截至这份文档编写时可能会有所变更。

slabs automove命令允许一个后台线程自主决定何时在slab class之间移动内存。它的实现和参数选项在最近几个版本中仍有变动。详情请查看wiki/邮件列表。

自动移动器可以在runtime使用命令开启或关闭。

slabs automove <0|1>
- 0|1|2 是否启用自动移动器的标识
服务端响应总会是"OK\r\n"

- <0> 表示设置线程为就绪状态
- <1> 表示运行内部的慢算法来选择需要移动的page
- <2> 是一种高度活跃的模式,会导致page每次都会被移动


LRU_Crawler 命令

----------- 
说明:该命令截至这份文档编写时可能会有所变更。

LRU_Crawler 是一个可选的后台线程,从尾部向首部遍历指定的slab classes,释放过期数据占用的内存空间。这对于既有很长也有很短生存时间,但是不被经常访问的数据项将非常有用。这个LRU_Crawler系统通常不会被使用到,而且会增加CPU使用率以及带来一点点延迟。

lru_crawler <enable|disable>- 启用或关闭LRU Crawler后台线程

该命令响应行,可能为下面其中一个:


- "OK" 表示crawler线程被成功启用或停止
- "ERROR [message]" 表示在启用或停止时发生某种错误

lru_crawler sleep <microseconds> 
- 在每检查一项数据,线程的睡眠时间。更小的睡眠时间对系统影响较大。
如果为"0"表示禁止睡眠,"1000000"(1秒)为最大值。


该命令响应行,可能为下面其中一个: 
- "OK" 
- "CLIENT_ERROR [message]" 表示格式错误或者数值超过边界。

lru_crawler tocrawl <32u>

- 设置每次运行请求的一个slab class可监视的最大数量(per run request是什么鬼)
作用是在找不到过期数据项时,防止扫描所有巨大的slabs。

该命令响应行,可能为下面其中一个: 
- "OK" - "CLIENT_ERROR [message]" 表示格式错误或者数值超过边界。

lru_crawler crawl <classid,classid,classid|all> 
- 读取一个或一组数字classid(例如:1,3,10)。指明crawler从尾部遍历所给的每一个classid,直到首部。
crawler不能停止或者重启,直到它完成之前一个请求。

(待续。。。)

0 0