2013年2月17日星期日

memcached简单的使用教程


这是工程应用性质的文章:memcached是数据快速存取的工具,wikipedia和facebook就用了它提高速度。具体情况可以wiki.

c/c++里面使用memcached本来是很简单的事情,但就是没有人说,非要我去读libmemcache的实例代码才行,manpage也没有说清楚(但还不得不看)。如果要使用memcached,步骤如下:

1 安装memcached
  你可以去官网 上下载,也可以sudo apt-get install memcached
2 测试你刚才的安装,
  比如运行 memcached -d -m 64 -l 127.0.0.1 -p 12300
  -d表示后台, -m 64表示使用64MB内存,-l 127.0.0.1 -p 12300 表示监听127.0.0.1:12300端口
  没有任何消息就是运行成功
3 安装libmemcached
  这个就不要apt了,因为没有精确的libmemcached包,乖乖去官网 下载吧。这个东西还需要libevent,这个没法apt,libevent安装的时候最好装到/usr/lib里面,不然libmemcached还不能运行。
4 测试libmemcached
  找一个文件比如test,然后运行memcp test --servers=127.0.0.1:12300
  这样就把test拷贝到memcached管理的内存里面了。
  memcat test --servers=127.0.0.1:12300
  看看是不是刚才的那个文件。

该装的全装了,我们可以改代码了。
(以下引自:wikipedia)

将纯粹使用数据库查询的程式码加上memcached支援是很简单的,假设这是原来的程式码:

function get_foo (int userid) {

   result = db_select("SELECT * FROM users WHERE userid = ?", userid);

   return result;

}

加上memcached的快取机制后:

function get_foo (int userid) {

    result = memcached_fetch("userrow:" + userid);

    if (!result) {

        result = db_select("SELECT * FROM users WHERE userid = ?", userid);

        memcached_add("userrow:" + userid,  result);

    }

    return result;

}

(wikipedia 引述完毕)

但我们需要初始化,而且需要c/c++的表述形式:
首先修改makefile,在LIBS里面加上-lmemcached,比如原来 gcc test.c,现在 gcc test.c -lmemcached。这个库就是libmemcached提供的。
然后添加#include<libmemcached/memcached.h>,这个文件也是libmemcached提供的。
主函数里面需要添加:
    memcached_st *memc;
    uint32_t  flags;
    memcached_return rc;
    memcached_server_st *servers;
    memc= memcached_create(NULL);

    servers= memcached_servers_parse("127.0.0.1:12300");
    memcached_server_push(memc, servers);
    memcached_server_list_free(servers);
    memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 0);
   
这就是初始化的全部代码,可以设置很多东西,不过我现在只要一个服务器,就看一句话:
    servers= memcached_servers_parse("127.0.0.1:12300");
这就是指明要连接到位于127.0.0.1监听12300端口的memcached程序. 其他都不管。

我最后用一段修改后的代码介绍两个函数,memcached_get和memcached_set,都可以man出来。

        char * result_str; /*这个就是查询的结果*/
        std::string query="要查询的数据名";

        result_str= memcached_get(memc, query.c_str(), strlen(query.c_str()),
                &result_str_length, &flags, &rc);

        if (rc == MEMCACHED_SUCCESS)
        {
            printf("%s",result_str);
            free(result_str); /*一定要free掉 memcached传回的数据*/

            continue;
        }
        else if (rc == MEMCACHED_NOTFOUND)
        {
            /*读取数据*/
            ...
            rc= memcached_set(memc, query.c_str(), strlen(query.c_str()),
                    str_result.c_str(), strlen(str_result.c_str()),
                    0, 0);
        }

这东西设计得还是很好用的,libmemcached好像是面向对象c语言风格的东西,好不好用就让我们拭目以待吧。
/////////////////////////////////////////////////////////////////////////////////
完整的例子:
#include <stdio.h>
#include <stdlib.h>
#include <libmemcached/memcached.h>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
 memcached_server_st *servers = memcached_servers_parse("127.0.0.1:22222");
 memcached_st *memc = memcached_create(NULL);
 memcached_server_push(memc, servers);
 memcached_server_list_free(servers);
 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 0);
 string strKey = "1";
 string strValue = "hello.world";
 memcached_return rc = memcached_set(memc, strKey.c_str(), strlen(strKey.c_str()), strValue.data(), strValue.size(), 0, 0);
 if (rc == MEMCACHED_SUCCESS)
 {
  printf("memcached_set ok! \n");
  size_t ValueLength = 0;
  uint32_t flags;
  char *pValue = memcached_get(memc, strKey.c_str(), strlen(strKey.c_str()), &ValueLength, &flags, &rc);
  if (rc == MEMCACHED_SUCCESS)
  {
   printf("memcached_get key=%s value=%s \n", strKey.c_str(), pValue);
   free(pValue);
  }
 }
 memcached_free(memc);
 return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////
memcached 命令
memcached 命令



comments 类型



1. storage commands: set add replace

2. retrieval commands: get

3. other commands: incr delete



error strings

1. "ERROR\r\n"

客户端发送了一个不存在的command



2. "CLIENT_ERROR <error>\r\n"

客户端的错误:客户端发送的数据或者格式方面有问题。 <error>表示具体错误的原因。



3. "SERVER_ERROR <error>\r\n"

服务器端的错误:服务器一系列的错误阻止了命令的执行。<error>表示具体错误的原因。当发生此错误时。服务器发送完了"SERVER_ERROR <error>\r\n"之后将会关闭connection。(这是唯一的关闭connection的情况)



descriptions of individual commands



1. storage commands

首先客户端向服务器按照如下格式发送命令行:

<command name> <key> <flags> <exptime> <bytes>\r\n



a) <command name> 可以是"set", "add", "replace"。

"set"表示按照相应的<key>存储该数据。

"add"表示按照相应的<key>添加该数据,但是如果该<key>已经存在则会操作失败。

"replace"表示按照相应的<key>替换数据,但是如果该<key>不存在则操作失败



b) <key> 客户端需要保存数据的key。



c) <flags> 是一个16位的无符号的整数(以十进制的方式表示)。该标志将和需要存储的数据一起存储,并在客户端get数据时返回。客户可以将此标志用做特殊用途,此标志对服务器来说是不透明的。



d) <exptime> 过期的时间。如果该数值为0表示存储的数据永远不过时(但是,该数据有可能被其他项所替换掉。因为服务器采用了LRU(最近最久没有使用)的算法替换)。如果非0(unix时间或者距离此时的秒数),当过期后,服务器可以保证用户得不到该数据(以服务器时间为标准)。



e) <bytes> 需要存储的字节数(不包含最后的"\r\n"),当用户希望存储空数据时,<bytes>可以为0



f) 最后客户端需要加上"\r\n"作为"命令头"的结束标志。



<data block>\r\n

紧接着"命令头"结束之后就要发送数据块(即希望存储的数据内容),最后加上"\r\n"作为此次通讯的结束。



reply

当以上数据发送结束之后,服务器将返回一个应答。可能有如下的情况:



a) "STORED\r\n"

表示存储成功



b) "NOT_STORED\r\n"

表示存储失败,但是该失败不是由于错误。通常这是由于"add"或者"replace"命令本身的要求所引起的,或者该项在删除队列之中(见delete命令)。



2 retrieval command

获取数据的格式:



get <key>*\r\n



a) <key>* 表示一个或者多个key(以空格分开)



b) "\r\n" 命令头的结束



reply

服务器端将返回0个或者多个的数据项。每个数据项都是由一个文本行和一个数据块组成。当所有的数据项都接收完毕将收到"END\r\n"



每一项的数据结构:

VALUE <key> <flags> <bytes>\r\n

<data block>\r\n



a) <key> 希望得到存储数据的key



b) <falg> 发送set命令时设置的标志项



c) <bytes> 发送数据块的长度(不包含"\r\n")



d) "\r\n" 文本行的结束标志



e) <data block> 希望接收的数据项。



f) "\r\n" 接收一个数据项的结束标志。



如果有些key出现在get命令行中但是没有返回相应的数据,这意味着服务器中不存在这些项,这些项过时了,或者被删除了。



3. delete

delete 命令格式:

delete <key> <time>\r\n



a) <key> 需要被删除数据的key



b) <time> 客户端希望服务器将该数据删除的时间(unix时间或者从现在开始的秒数)



c) "\r\n" 命令头的结束



reply



a) "DELETED\r\n" 删除成功



b) "NOT_FOUND\r\n" 需要删除的key不存在



ps:"flush_all" command 可以所有项都无效。



4. increment/decrement



command "incr" "decr" 是用来改变数据项数值的命令。设置数据项的数据被认为是一个10进制的无符号的整数。如果当前设置的值不能够被转换则认为是0.如果该数据项的key不存在,则执行命令失败!



命令格式:



incr <key> <value>\r\n

or

decr <key> <value>\r\n



a) <key> 数据项的key



b) <value> 用户希望增加/减少的数据的数值.该数值是一个32位十进制的无符号整形变量。



c) "\r\n" 命令行结束标志



reply



a) "NOT_FOUND\r\n" 没有找到需要操作的项。



b) "<value>\r\n" <value>数据项有效期的最新剩余时间。



注意:

a) 如果一个数据项的有效期被设置为0,这时使用decr命令是无法减少数据。



b) 如果要执行 incr key -1 的操作不会有什么问题,结果和你希望的一样。但是,执行decr -1时的结果一定会让你觉得很意外,因为它的结果无论key的数据是什么结果的都是0.原因是:在这两个命令的执行过程中都是吧-1当做一个无符号的整形处理的。



c) 执行decr命令时数据的长度不会随之而减小,而是在返回数据的后面填补空格。但是执行incr命令越界后会自动的增加数据的位数。





5. 其他命令



"stats": 用来查询服务器提供的内部数据。



stats <args>\r\n

查询特定的数据



reply



STAT <name> <value>\r\n

...

END\r\n



"quit"

"quit\r\n": 退出程序


///////////////////////////////////////////////////////////////////////////////////////////////////


对于 Memcached 缓存系统的基本介绍、安装以及应用 之前有一编文章说过,下面主要是对使用Memcached系统的基本命令以及协议作个简单的分析,个人学习的笔记,呵呵。还希望能给需要的筒子一点参考:

一、Memcache面向对象的常用接口包括:
Memcache::connect -- 打开一个到Memcache的连接
Memcache::pconnect -- 打开一个到Memcache的长连接
Memcache::close -- 关闭一个Memcache的连接
Memcache::set -- 保存数据到Memcache服务器上
Memcache::get -- 提取一个保存在Memcache服务器上的数据
Memcache::replace -- 替换一个已经存在Memcache服务器上的项目
Memcache::delete -- 从Memcache服务器上删除一个保存的项目
Memcache::flush -- 刷新所有Memcache服务器上保存的项目(类似于删除所有的保存的项目)
Memcache::getStats -- 获取当前Memcache服务器运行的状态

For More: http://cn.php.net/memcache

二、查看系统的运行状态:


pid               Process id of this server process (memcache服务器的进程ID)
uptime            Number of seconds this server has been running (服务器已经运行的秒数)
time              Current UNIX time according to the server (服务器当前的UNIX时间)
version           Version string of this server (memcache版本)
pointer_size      Current system pointer 当前操作系统的指针大小(32位系统一般是32bit)
rusage_user       Accumulated user time for this process (该进程累计的用户时间(秒:微妙))
rusage_system     Accumulated system time for this process (该进程累计的系统时间(秒:微妙))
curr_items        Current number of items stored by the server (服务器当前存储的内容数量)
total_items       Total number of items stored by this server ever since it started (服务器启动以来存储过的内容总数)
bytes             Current number of bytes used by this server to store items (服务器当前存储内容所占用的字节数)
curr_connections  Number of open connections (当前打开着的连接数量)
total_connections Total number of connections opened since the server started running (服务器运行以来接受的连接总数)
connection_structures Number of connection structures allocated by the server (服务器分配的连接结构的数量)
cmd_get             Cumulative number of retrieval requests (get命令(获取)总请求次数)
cmd_set             Cumulative number of storage requests (set命令(保存)总请求次数)
get_hits            Number of keys that have been requested and found present (请求成功的总次数)
get_misses          Number of items that have been requested and not found (请求失败的总次数)
threads             Current number of thread (当前线程数)
bytes_read          Total number of bytes read by this server from network (服务器从网络读取到的总字节数)
bytes_written       Total number of bytes sent by this server to network (服务器向网络发送的总字节数)
limit_maxbytes      Number of bytes this server is allowed to use for storage. (服务器在存储时被允许使用的字节总数)
evictions           Number of valid items removed from cache to free memory for new items (为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items))

其中,最关注最多的几个参数:
uptime:是memcached运行的秒数。
cmd_get:是查询缓存的次数。
cmd_get/uptime 结果是平均每秒请求缓存的次数——结果值越大,说明Memcached的利用率越高,站点的访问量大,如果太低,用文件系统缓存就可以了,根本不会体现出使用memcached的强大性能。
cmd_set:是设置key=>value的次数。整个memcached是个大hash,用cmd_get没有找到的内容,就会调用一下cmd_set写进缓存里。
get_hits:是缓存命中的次数。所谓的命中率 = get_hits/cmd_get * 100%。
get_misses:是缓存未命中的次数。get_misses加上get_hits就等于cmd_get。
stats:显示服务器信息、统计数据等
stats reset:清空统计数据

stats slabs:显示各个slab的信息,包括chunk的大小、数目、使用情况等
stats items:显示各个slab中item的数目和存储时长(最后一次访问距离现在的秒数)
quit:退出

三、利用shell命令操作Memcached
1、数据存储(key为wan,value为123)

2、数据取回

3、替换数据(将以wan为key存储的值替换为122)

4、数值增加 1

5、数值减少 2

6、数据删除

7、查看Memcached当时状态
printf "stats\r\n" | nc 127.0.0.1 11211
8、查看Memcached实时状态

watch "printf 'stats\r\n' | nc 127.0.0.1 11211"



Memcached protocol 中英文档可以参考:

http://blog.s135.com/book/memcached/

四. 查看slabs的使用状况
使用memcached的创造着Brad写的名为 memcached-tool 的Perl脚本,可以方便地获得slab的使用情况(它将memcached的返回值整理成容易阅读的格式)。可以从下面的地址获得脚本:
http://code.sixapart.com/svn/memcached/trunk/server/scripts/memcached-tool
[root@localhost html]# vim memcached-tool
[root@localhost html]# chmod +x memcached-tool
[root@localhost html]# ./memcached-tool 127.0.0.1:11211
  #  Item_Size   Max_age  1MB_pages Count   Full?
  1      80 B        0 s               1           0      no
  2     104 B       12175 s         1           1      no
  3     176 B    1339587 s       33       196567  yes

各列的含义:
#: slab class编号
Item_Size: Chunk大小
Max_age: LRU内最旧的记录的生存时间
1MB_pages: 分配给Slab的页数
Count: Slab内的记录数
Full?: Slab内是否含有空闲chunk

五. 也可以图形化监控 Memcached 的运行状态
http://livebookmark.net/journal/2008/05/21/memcachephp-stats-like-apcphp/
是一个PHP源文件,只需要修改源码中的用户名、密码以及数组$MEMCACHE_SERVERS 就可以了。

没有评论:

发表评论