buhao 发表于 2017-4-15 14:11:21

Memcache初学之二 服务器端操作memcache

 Memcached 支持两种主要的协议,经典的 ASCII 文本协议和新的二进制协议。文本协议非常简单,能很方便的编写客户端和调试问题,但是二进制协议提供更强大的功能。
 
文本协议的 TCP 协议应用比较广泛,本文主要详细介绍 TCP 文本协议。如果想了解 UDP 协议和二进制协议,请参考官方文档。
官方文本协议: http://github.com/memcached/memcached/blob/master/doc/protocol.txt
官方二进制协议: http://code.google.com/p/memcached/wiki/BinaryProtocolRevamped
 
协议命令格式
Java代码  


[*]<command name> <key> <flags> <exptime> <bytes> \r\n  
[*]  
[*]cas <key> <flags> <exptime> <bytes> <cas unique> \r\n  


[*] <command name> : "set", "add", "replace", "append" or "prepend"
[*]"set" :“存储这个数据”,一般是更新已有的缓存,也可以用于新增。
[*]"add" :新增缓存,缓存中不存在新增的KEY。
[*]Replace:替换现有的缓存,缓存中一定已经存储KEY
[*]Append:在现有的缓存数据后添加缓存数据。
[*]Prepend:在现有的缓存数据前添加缓存数据
[*]Cas:check and set操作,存储缓存,前提是在check后没有其它人修改过数据,用于多客户端同时设置相同的KEY时的原子操作。
[*]<key>:缓存的KEY
[*]<flags>:最开始是16位的无符号整数,现在的版本一般是32位。用户客户端存储自定义标记数据。
[*]<exptime>:缓存过期时间。0表示永不过期,可以是Unix time或当前服务器时间的偏移量(秒为单位),如果你想设置当前时间后1分钟过期,则此参数为60。
[*]<bytes>:缓存数据的长度
[*]<cas unique>:unique 64-bit value of an existing entry,cas操作的时候回传的值,用于服务器端判断缓存是否改变。
[*]"noreply":服务器不响应处理结果。
[*]<data block>\r\n: 缓存数据块,\r\n结束
[*]"STORED\r\n":表示存储成功
[*]"NOT_STORED\r\n":表示未存储,但并不是错误。如:对已经有的KEY使用add
[*]"EXISTS\r\n":表示使用cas命令设置数据未成功,在你最后一次获取数据后,数据已经被其它人修改。
[*]"NOT_FOUND\r\n":表示使用cas存储数据时候,key不存储

错误指令
每一个由客户端发送的命令,都可能收到来自服务器的错误字串回复。这些错误字串会以三种形式出现:
ERROR\r\n
意味着客户端发送了不存在的命令名称。
"CLIENT_ERROR <error>\r\n
意味着输入的命令行里存在一些客户端错误,例如输入未遵循协议。 <error> 部分是人类易于理解的错误解说
SERVER_ERROR <error>\r\n
意味着一些服务器错误,导致命令无法执行。 <error> 部分是人类易于理解的错误解说。在一些严重的情形下(通常应该不会遇到),服务器将在发送这行错误后关闭连接。这是服务器主动关闭连接的唯一情况
 
add/set/replace/append/prepend
保持指令包括: add,set , Replace ,append, Prepend 。在分布式环境中,这些命令都不能保证原则性操作,需要使用 cas 对缓存进行存储操作。
 
Java代码  


[*]Add/set/Replace/append/Prepend <key> flags <exptime> <bytes>\r\n  
[*]data\r\n  

   
 
add : 添加新的缓存,不能覆盖。如果添加一个存在的缓存,服务器不会执行和报错,只会返回 NOT_STORED。
Java代码  


[*]telnet localhost 11211  
[*]add key 0 0 5  
[*]12345  
[*]STORED  
[*]add key 0 0 1  
[*]1  
[*]NOT_STORED  

 
set :设置缓存,功能和 add 基本相同,可能 覆盖 。
Java代码  


[*]set key 0 0 2  
[*]12  
[*]STORED  

 

replace : 仅当键已经存在时, replace 命令才会替换缓存中的键。如果缓存中不存在键,那么您将从 memcached 服务器接受到一条 NOT_STORED 响应
 
 
Java代码  


[*]replace key 0 0 3  
[*]123  
[*]STORED  
[*]replace key1 0 0 3  
[*]123  
[*]NOT_STORED    //key1 不存在  

 
append :是在现有缓存数据后面新增数据。如果 key 不存在,服务器响应 NOT_STORED
 
Java代码  


[*]get key  
[*]VALUE key 0 3  
[*]123  
[*]END  
[*]append key 0 0 2  
[*]45  
[*]STORED  
[*]get key  
[*]VALUE key 0 5  
[*]12345  
[*]END  

   
prepend 是在现有缓存数据前面新增数据。如果 key 不存在,服务器响应 NOT_STORED
Java代码  


[*]get key  
[*]VALUE key 0 5  
[*]12345  
[*]prepend key 0 0 7  
[*]prepend  
[*]STORED  
[*]get key  
[*]VALUE key 0 12  
[*]prepend12345  
[*]END  
[*]prepend key1 0 0 1  
[*]1  
[*]NOT_STORED  

 
get/gets
Java代码  


[*]get <key>*\r\n      // 获取缓存的值  
[*]gets <key>*\r\n      // 获取缓存的值和版本号 <cas unique>  

 
key是缓存的key,命令以\r\n结束。
返回

Java代码  


[*]VALUE <key> <flags> <bytes> [<cas unique>]\r\n  
[*]<data block>\r\n  

 
 
<flags>是你添加和设置缓存的时候设置的值。一般用于自定义标记缓存数据的特殊意义,对memcached服务无意义,客户端自定义其含义。例如:设置缓存的时候,设置1表示该数据是对象json序列化,2表示二进制序列化。
<cas unique>:是一个64位的整数,在服务器端唯一,每次针对缓存的操作就会加一,类似于svn的版本号的东东。
 
例:
Java代码  


[*]@hadoop00 bin]# telnet 192.168.221.10 11211  
[*]Trying 192.168.221.10...  
[*]Connected to hadoop00 (192.168.221.10).  
[*]Escape character is '^]'.  
[*]add key1 0 0 12  
[*]hello first!  
[*]STORED  
[*]  
[*]get key1  
[*]VALUE key1 0 12  
[*]hello first!  
[*]END  
[*]  
[*]gets key1  
[*]VALUE key1 0 12 2  
[*]hello first!  
[*]END  
[*]  
[*]set key1 1 0 13  
[*]hello second!  
[*]STORED  
[*]   
[*]gets key1  
[*]VALUE key1 1 13 3  
[*]hello second!  
[*]END   

   
 
第 1 段:添加缓存 key1=hello first!,flags=0
第 2 段: get 获取缓存 key1 的值, flags=0
第 3 段: gets 获取缓存  key1 的值, flags=0 ; cas unique=2
第 4 段: set 缓存 key1 的值为 hello second! ,设置 flags=1
第 5 段: gets 获取 key1 的值, flags=1; cas unique=3
 
delete
delete:删除一个存在的缓存
Java代码  


[*]get key  
[*]VALUE key 0 12  
[*]prepend12345  
[*]END  
[*]delete key  
[*]DELETED  
[*]get key  
[*]END  

 
 
incr/decr 
如果缓存数据中存储的是数字形式的字符串,则可以使用 incr/decr 对数据进行递增和递减操作,服务器响应操作过的结果。操作后的值不会为负数。
格式: incr/decr key number\r\n
Java代码  


[*]add key 0 0 2  
[*]10  
[*]STORED  
[*]incr key 1    // 递增 1  
[*]11  
[*]decr key 2    // 递减 2  
[*]9  
[*]add key1 0 0 2  
[*]aa  
[*]STORED  
[*]incr key1 1   // 对非数字的缓存操作会返回错误  
[*]CLIENT_ERROR cannot increment or decrement non-numeric value  

 
stats
命令 "stats" 被用于查询服务器的运行状态和其他内部数据。有两种格式。不带参数的:
stats\r\n
stats <args>\r\n    // 具体参数据说在变动,不过也意义不打,直接用无参数就可以了。
 
 
Key
数据类型
说明
pid
32u
服务器进程 ID
uptime
32u
服务器运行时间,单位秒
time
32u
服务器当前的 UNIX 时间
version
string
服务器的版本号
pointer_size
32u
服务器操作系统位数
curr_connections
32u
当前连接数
total_connections
32u
服务器启动后总连接数
connection_structures
32u
服务器分配的连接结构的数量
cmd_get
64u
获取请求总数
cmd_set
64u
存储请求总数
cmd_flush
64u
 
get_hits
64u
获取成功的总次数,命中次数
get_misses
64u
获取失败的总次数
delete_misses
64u
删除失败次数
delete_hits
64u
删除命中
incr_misses
64u
递增失败次数
incr_hits
64u
递增命中
decr_misses
64u
递减命中
decr_hits
64u
递减失败次数
cas_misses
64u
Cas 原子设置操作失败次数
cas_hits
64u
Cas 命中
cas_badval
64u
Cas 操作找到 key, 但是版本过期,没有设置成功
auth_cmds
64u
认证次数(包括成功和失败)
auth_errors
64u
认证失败次数
bytes_read
64u
 
总共获取的数据量
bytes_written
64u
总写入数量数
limit_maxbytes
32u
总允许写入的数据量,和分配的内存有关
  accepting_conns
 
未找到文档,官方协议为说明
listen_disabled_num
 
未找到文档,官方协议为说明
  threads
 
未找到文档,官方协议为说明
conn_yields
 
未找到文档,官方协议为说明
bytes
64u
已用缓存空间
curr_items
32u
当前缓存 item 数量
total_items
32u
从服务启动后,总的存储缓存 item 数量
evictions
64u
通过删除 item 释放内存的次数
 
 
 
 
flush_all
 
“ flush_all ” 命令有一个可选的数字参数。它总是执行成功,服务器会发送 “OK\r\n” 回应。它的效果是使已经存在的项目立即失效(缺 省),或在指定的时间后。此后执行取回命令,将不会有任何内容返回(除非重新存储同样的键名)。 flush_all 实际上没有立即释放项目所占用的内存,而是在随后陆续有新的项目被储存时执行。flush_all 效果具体如下:它导致所有更新时间早于 flush_all 所设定时间的项目,在被执行取回命令时命令被忽略。
 
Java代码  


[*]flush_all  
[*]OK  
[*]flush_all 10  
[*]OK  

version
 
版本查询: version \r\n
 
Java代码  


[*]version  
[*]VERSION 1.4.4-14-g9c660c0  

quit
 
CAS 协议解决这种并发修改问题。有线程试图修改当前 key-value 对的 value 时,先由 gets 方法得到 item 的版本号,操作完成提交 数据时,使用 cas 方法谨慎变更,如果在本地对 item 操作过程中这个 key-value 对在Memcached server 端被其它线程更改过,就放弃此次修改 (乐观锁)
cas 命令只能用于修改已经有的参数,对应新增操作会返回: NOT_FOUND
 
Java代码  


[*]add caskey 0 0 1        //添加一个缓存key=caskey  
[*]1  
[*]STORED  
[*]gets caskey         //获取caskey的数据和版本号  
[*]VALUE caskey 0 1 15     //15是当前版本号  
[*]1  
[*]END  
[*]set caskey 0 0 26       //模拟其它线程修改了caskey的值  
[*]anther thread modify value  
[*]STORED  
[*]cas caskey 0 0 1 15     //当前线程通过版本号15设置数据失败  
[*]2  
[*]EXISTS  

 参考 http://acooly.iteye.com/blog/1120346
页: [1]
查看完整版本: Memcache初学之二 服务器端操作memcache