写点什么

网络协议之:memcached text protocol 详解

作者:程序那些事
  • 2022 年 5 月 09 日
  • 本文字数:3250 字

    阅读完需:约 11 分钟

网络协议之:memcached text protocol详解

简介

用过缓存系统的肯定都听过 memcached 的大名,memcached 是一个非常优秀的分布式内存缓存系统,应用非常的广泛。Memcached 不仅仅是 Web 缓存,它更是一个通用的数据缓存,基本上你可以将任何东西存入 memcached 中,它的分布式设计具有很好的可扩展性和灵活性。


Memcached 是一个客户端-服务器端的架构模式。一般来说,在服务器上搭建好 Memcached 的服务器端,接下来就可以使用 Memcached 的客户端和服务器端进行交换了。


作为客户端和服务器端的模型,两者的通讯肯定是有特定的协议的,适用于 memcached 的协议就叫做 memcached protocol。


memcached 的协议有两种,分别是 text 协议和 binary 协议。本文将会详细讲解 memcached text protocol 的定义。

memcached protocol 介绍

memcached 可以看做是一个简单的 key-value 的存储系统,客户端通过 key 来请求服务器端的数据,服务器端通过 key 的 hash 值来查找对应的数据,然后返回给客户端。


memcached 中的 key 长度一般不能超过 250 个字符。key 不能包含控制字符或空白字符。


为了保证客户端和服务器端的消息通讯顺畅,一般来说都会制定特殊的客户端和服务器端的通讯协议,这个协议就叫做 protocol。


什么是 protocol 呢?protocol 听起来很高深很神秘,但是实际上 protocol 就是约定好的双方交互的消息格式。


对于 memcached 来说,memcached 同时支持 UDP 和 TCP 协议,并且提供了两种协议方式,分别是“文本协议”和“二进制协议”。


其中文本协议是在第一个版本就支持的协议,而二进制协议是在 v1.4 之后才支持的。


文本协议和二进制协议都支持同样的命令,两者的唯一区别就是二进制协议具有更低的性能延迟和更好的可扩展性,而文本协议的有点就是它的可调试性能更好。


memcached text 协议包含两部分数据,文本行和非结构化数据。前者是来自客户端的命令或来自服务器的响应,后者代表客户端访问的数据。命令以\r\n 结尾,数据可以用\r、\n 或\r\n,表示数据部分的结束。

memcached 支持的命令

memcached 支持三种命令,分别是存储命令,读取命令和其他命令。

存储命令

memcached 中的存储命令总共有 6 个,分别是“set”、“add”、“replace”、“append”、"prepend" 和 "cas"。


首先,客户端发送如下所示的命令行:


command key [flags] [exptime] length [noreply]
复制代码


另外 cas 命令的格式和其他几个不太一样:


cas key [flags] [exptime] length [casunique] [noreply]
复制代码


上面的命令中,command 代表的是命令的名字,也就是上面的“set”、“add”、“replace”、“append”和"prepend"。


set 表示给 key 设置一个值。


Add 表示如果 key 不存在的话,就添加。


replace 用来替换已知 key 的 value。


append 表示将提供的值附加到现有 key 的 value 之后,是一个附加操作。


prepend 将当前 key 对应的 value 添加到提供的值后面。


cas 是一个原子操作,只有当 casunique 匹配的时候,才会设置对应的值。


flags 是一个非常有趣的参数,这个参数对于 memcached server 来说是透明的,这个参数只是用来标记客户端命令的类型,并不会被服务器端识别。另外 flags 的长度在不同的 memcached 版本中也有所不同,在 memcached 1.2.0 或者根据低级的版本中,flags 是一个 16-bit 的整数。在 memcached 1.2.1 或以上的版本,flags 是一个 32-bit 的整数。


exptime 是过期时间,0 表示不会过期。


length 是以 byte 表示的 value 的长度,这个值并不包含 value 中的结束符"\r\n"。


casunique 是一个 64-bit 的现有 entry 的唯一值。


noreply 告诉服务器端,这是个不需要 reply 的命令。


在发送完命令行之后,客户端还需要发送数据块:


<data block>\r\n
复制代码


举个例子,我们想要将 jack 这个值设置到 student 这个 key 上,那么对应的命令应该如下所示:


set student 0 0 4\r\njack\r\n
复制代码


对应的客户端收到的服务器端的返回可能有这些值:


  • "STORED\r\n",表示存储成功。

  • "NOT_STORED\r\n" 表示数据因为某些错误未存储成功。这通常意味着不满足“add”或“replace”命令的条件。

  • "EXISTS\r\n" 表示要设置的值在上次进行 cas 操作之后已经被修改了。

  • "NOT_FOUND\r\n" 表示要设置的值用在 cas。

读取命令

memcached 的读取命令有 4 个,分别是“get”、“gets”、“gat”和“gats,这些命令的格式如下:


get <key>*\r\ngets <key>*\r\ngat <exptime> <key>*\r\ngats <exptime> <key>*\r\n
复制代码


memcached 中的读取命令后面不需要跟额外的数据块。


服务器端会根据接收到的 key 进行查询,每个 key 返回一条数据,格式如下:


VALUE <key> <flags> <bytes> [<cas unique>]\r\n<data block>\r\n
复制代码


在所有的数据都传输完毕之后,服务器端会发送"END\r\n"表示传输完毕。


这里的 key 表示查询传入的 key。


flags 是存储命令传入的 flags。


bytes 是后面 data block 的长度。


cas unique 是当前 item 的唯一标记,在 gets 或者 gats 命令中返回。


data block 是当前 item 具体的返回值。


上面我们提到了 4 个读取的命令,那么他们有什么区别呢?


首先是 get 和 gets 的区别,get 用于获取 key 的 value 值,若 key 不存在,返回空。支持多个 key。 gets 用于获取 key 的带有 CAS 令牌值的 value 值,若 key 不存在,返回空。支持多个 key。 他们的区别在于 gets 会返回多一个 cas unique 值。


gat 和 get 的区别是,gat 是 get+touch 的命令综合体,除了返回当前值之外,还会更新 key 的过期时间。

常用的其他命令

除了存储和获取之外,还有一些常用的其他命令。为什么这些命令被叫做第三类命令呢?这是因为这些命令只需要一个命令行即可,并不需要向服务器端传入额外的数据块。


下面是删除命令的格式:


delete <key> [noreply]\r\n
复制代码


key 是要删除的对象。


noreply 表示是否需要收到服务器的返回值。


对应的服务器端返回值可能有两个:


  • "DELETED\r\n" 表示删除成功

  • "NOT_FOUND\r\n" 表示要删除的对象并不存在。


下面是 Increment/Decrement 命令的格式:


incr <key> <value> [noreply]\r\ndecr <key> <value> [noreply]\r\n
复制代码


key 是要修改的对象。


value 是要添加或者减少的值,它必须是一个 64-bit 无符号整数。


noreply 表示是否需要收到服务器的返回值。


服务器端的返回可能有两个:


  • "NOT_FOUND\r\n" 表示要修改的对象没有找到

  • "value\r\n" 返回修改成功之后的值


还有一个常用的是修改 key 过期时间的 touch 命令:


touch <key> <exptime> [noreply]\r\n
复制代码


key 是要修改的对象。


exptime 是过期时间。


noreply 表示是否需要收到服务器的返回值。


服务器端的返回值有两种:


  • "TOUCHED\r\n" 表示修改成功。

  • "NOT_FOUND\r\n" 表示要修改的对象不存在。


当然 memcached 支持的命令远不止上面所讲的这些。我们只是从中挑选出了最常用的一些命令进行讲解。

memcached 服务器的返回值

上面在讲解具体的命令的时候有提到服务器的返回值,这里再总结一下,memcached 服务器端的返回值有下面几种:



注意,上面所有的返回值都以"\r\n"结尾。

支持 UDP 协议

上面我们讲的都是 TCP 协议的报文格式。事实上 memcached 还支持 UDP 协议。


但是因为 UDP 不保证可靠性的特征,所以使用 UDP 的场合一般在做缓存的查询应用中,即使查询失败,也只是被看做是缓存没有被命中而已,并不会影响到数据的准确性。


事实上 UDP 的数据包和 TCP 的数据包格式基本一样,只不过多了一个简单的帧头。并且所有的请求都必须在单个 UDP 数据包中完成。


注意,这里只有请求才有这个要求,服务器端的返回并没有这个限制。


在 UDP 中帧头长 8 个字节,其中 0-1 个字节表示的是请求 ID,请求 ID 是由客户端生成的一个单调递增的值。服务器端将会使用这个 ID 来标记是对哪个请求的响应。特别是在有服务器端有多个响应的情况下。


2-3 个字节表示的是序列号,它的取值范围是 0 到 n-1,其中 n 是消息中总的报文个数,也就是 4-5 个字节所表示的。


最后的 6-7 字节是保留字节,以备将来使用,现在设置为 0。

总结

以上就是对 memcached 协议的介绍,通常来说我们使用 memcached 都是通过 memcached 客户端来进行的,如果有细心的朋友可能会发现,客户端使用的命令和协议中的命令差别不大,这是因为客户端就是对这些底层协议的封装,然后暴露给用户一个更加简单易操作的接口。


更多内容请参考 http://www.flydean.com/23-memcached-text-protocol/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 2022 年 05 月 09 日阅读数: 11
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
网络协议之:memcached text protocol详解_Java_程序那些事_InfoQ写作社区