4月 122011
 

memcached 1.2.8

-p <num>      TCP port number to listen on (default: 11211)

-U <num>      UDP port number to listen on (default: 11211, 0 is off)

-s <file>     unix socket path to listen on (disables network support)

-a <mask>     access mask for unix socket, in octal (default 0700)

-l <ip_addr>  interface to listen on, default is INDRR_ANY

-d            run as a daemon

-r            maximize core file limit

-u <username> assume identity of <username> (only when run as root)

-m <num>      max memory to use for items in megabytes, default is 64 MB

-M            return error on memory exhausted (rather than removing items)

-c <num>      max simultaneous connections, default is 1024

-k            lock down all paged memory.  Note that there is a

              limit on how much memory you may lock.  Trying to

              allocate more than that would fail, so be sure you

              set the limit correctly for the user you started

              the daemon with (not for -u <username> user;

              under sh this is done with ‘ulimit -S -l NUM_KB’).

-v            verbose (print errors/warnings while in event loop)

-vv           very verbose (also print client commands/reponses)

-h            print this help and exit

-i            print memcached and libevent license

-P <file>     save PID in <file>, only used with -d option

-f <factor>   chunk size growth factor, default 1.25

-n <bytes>    minimum space allocated for key+value+flags, default 48

-R            Maximum number of requests per event

              limits the number of requests process for a given con nection

              to prevent starvation.  default 20

-b            Set the backlog queue limit (default 1024)

——————————————————————-

 

memcached 1.4.5

-p <num>      TCP port number to listen on (default: 11211)

-U <num>      UDP port number to listen on (default: 11211, 0 is off)

-s <file>     UNIX socket path to listen on (disables network support)

-a <mask>     access mask for UNIX socket, in octal (default: 0700)

-l <ip_addr>  interface to listen on (default: INADDR_ANY, all addresses)

-d            run as a daemon

-r            maximize core file limit

-u <username> assume identity of <username> (only when run as root)

-m <num>      max memory to use for items in megabytes (default: 64 MB)

-M            return error on memory exhausted (rather than removing items)

-c <num>      max simultaneous connections (default: 1024)

-k            lock down all paged memory.  Note that there is a

              limit on how much memory you may lock.  Trying to

              allocate more than that would fail, so be sure you

              set the limit correctly for the user you started

              the daemon with (not for -u <username> user;

              under sh this is done with ‘ulimit -S -l NUM_KB’).

-v            verbose (print errors/warnings while in event loop)

-vv           very verbose (also print client commands/reponses)

-vvv          extremely verbose (also print internal state transitions)

-h            print this help and exit

-i            print memcached and libevent license

-P <file>     save PID in <file>, only used with -d option

-f <factor>   chunk size growth factor (default: 1.25)

-n <bytes>    minimum space allocated for key+value+flags (default: 48)

-L            Try to use large memory pages (if available). Increasing

              the memory page size could reduce the number of TLB misses

              and improve the performance. In order to get large pages

              from the OS, memcached will allocate the total item-cache

              in one large chunk.

-D <char>     Use <char> as the delimiter between key prefixes and IDs.

              This is used for per-prefix stats reporting. The default is

              ":" (colon). If this option is specified, stats collection

              is turned on automatically; if not, then it may be turned on

              by sending the "stats detail on" command to the server.

-t <num>      number of threads to use (default: 4)

-R            Maximum number of requests per event, limits the number of

              requests process for a given connection to prevent 

              starvation (default: 20)

-C            Disable use of CAS

-b            Set the backlog queue limit (default: 1024)

-B            Binding protocol – one of ascii, binary, or auto (default)

-I            Override the size of each slab page. Adjusts max item size

              (default: 1mb, min: 1k, max: 128m)

对于新的版本,增加了多线程处理机制,这样设定可能会提高memcache官方提供95%的命中率的问题。

对于memcache的使用,尽量使用内网,减少服务器连接的时间。

对于高并发的处理,memcache如果效果不太理想,可以尝试使用magent,memcache负载均衡。

 Posted by at 下午 9:19
4月 122011
 

使用PHP的memcache模块写了一个访问tokyotrant的long-live程序,因为是long-live的,所以我就connect一次之后一直使用了,理论上我connect之后就可以一直使用,中间不会出现重新连接的问题,为了确认我的推断,启动进程之后,我用strace跟踪了一些进程,令我意外的是,隔一段时间连接就会关闭,然后重新连接,怎么回事呢?

我怀疑两个方面:
1. 我的程序有问题
2. server端有问题,用一段时间会关掉我的连接

首先,我用了大约1个小时的时间,简直把我的程序拆的支离破碎了,结果没有发现哪里有问题。
其次,我使用tcpdump观察了一下,发现主动关闭连接的不是server端,而是我的程序。
百思不得其解。这件事简直成了我的一块心病。

隔了一段时间,当我再次使用tcpdump观察的时候,结果如下:
1.   21:27:20.273522 IP 10.55.38.62.60953 > 10.55.38.70.2004: . ack 132 win 501 <nop,nop,timestamp 3026990738 3683027032>
2.  21:27:20.273757 IP 10.55.38.62.60953 > 10.55.38.70.2004: P 20:142(122) ack 132 win 501 <nop,nop,timestamp 3026990738 3683027032>
3.  21:27:20.273871 IP 10.55.38.70.2004 > 10.55.38.62.60953: . ack 142 win 255 <nop,nop,timestamp 3683027032 3026990738>
4. 21:27:21.273955 IP 10.55.38.62.60953 > 10.55.38.70.2004: F 142:142(0) ack 132 win 501 <nop,nop,timestamp 3026991738 3683027032>
5. 21:27:21.274038 IP 10.55.38.62.37298 > 10.55.38.70.2004: S 3948732568:3948732568(0) win 5792 <mss 1460,sackOK,timestamp 3026991738 3683027542,nop,wscale 7>
6. 21:27:21.274165 IP 10.55.38.70.2004 > 10.55.38.62.37298: S 34634952:34634952(0) ack 3948732569 win 5792 <mss 1460,sackOK,timestamp 3683028032 3026991738,nop,wscale 7>
21:27:21.274185 IP 10.55.38.62.37298 > 10.55.38.70.2004: . ack 1 win 46 <nop,nop,timestamp 3026991738 3683028032>
21:27:21.274196 IP 10.55.38.62.37298 > 10.55.38.70.2004: P 1:123(122) ack 1 win 46 <nop,nop,timestamp 3026991738 3683028032>
21:27:21.274320 IP 10.55.38.70.2004 > 10.55.38.62.37298: . ack 123 win 46 <nop,nop,timestamp 3683028032 3026991738>
21:27:21.313329 IP 10.55.38.70.2004 > 10.55.38.62.60953: . ack 143 win 255 <nop,nop,timestamp 3683028072 3026991738>
21:27:21.533806 IP 10.55.38.70.2004 > 10.55.38.62.37298: P 1:9(8) ack 123 win 46 <nop,nop,timestamp 3683028292 3026991738>
21:27:21.533822 IP 10.55.38.62.37298 > 10.55.38.70.2004: . ack 9 win 46 <nop,nop,timestamp 3026991998 3683028292>
21:27:22.604843 IP 10.55.38.70.2004 > 10.55.38.62.60953: P 132:140(8) ack 143 win 255 <nop,nop,timestamp 3683029363 3026991738>
21:27:22.604859 IP 10.55.38.62.60953 > 10.55.38.70.2004: R 3898017016:3898017016(0) win 0
21:27:24.072995 IP 10.55.38.62.37298 > 10.55.38.70.2004: P 123:143(20) ack 9 win 46 <nop,nop,timestamp 3026994537 3683028292>

============================================
我意外地发现有一个reset包,感觉很奇怪,顺着 60953 端口网上查,发现:
第2个包: 向server端发送数据
第3个包: server端回复收到数据
第4个包: 按说应该server端返回响应数据,但是这里却是client端发了一个finish包
观察第3个包与第4个包之间的时间间隔,基本是1s, 这令我想起了memcache的默认超时时间也是1s,是巧合?显然不是。因为:
第5个包: client端重新发起了连接操作
显然是超时了, 于是重连有了答案。

当然,虽然client关闭了连接,server端却还没有关闭,直到 21:27:22.604859 的时候,服务器端给出了响应数据,但是client已经关闭了,所以出现了被reset的现象。

==========================================
还有一个问题:
我的程序里面是做了容错处理的,但是我的容错策略是,如果出错了,则sleep(2);之后重新连接; 显然不符合上面的表现,怀着万般不解的心情开始看php的memcache模块的源码;
在memcache.c中:

Memcach.c
  1.     
    int mmc_pool_store(mmc_pool_t *pool, const char *command, int command_len, const char *key, int key_len, int flags, int

        

  2.     
     expire, const char *value, int value_len TSRMLS_DC) /* {{{ */

        

  3.     
    {

        

  4.     
        mmc_t *mmc;

        

  5.     
        char *request;

        

  6.     
        int request_len, result = 1;

        

  7.     
        char *key_copy = NULL, *data = NULL;

        

  8.     
    //…

        

  9.     
        while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) {

        

  10.     
            if ((result = mmc_server_store(mmc, request, request_len TSRMLS_CC)) < 0) {

        

  11.     
                mmc_server_failure(mmc TSRMLS_CC);

        

  12.     
            }    

        

  13.     
        }

        

  14.     
      // …

        

  15.     
    }

        

  16.     
     

        

  17.     
    // ..

        

  18.     
    int mmc_server_failure(mmc_t *mmc TSRMLS_DC) /*

        

  19.     
        determines if a request should be retried or is a hard network failure {{{ */

        

  20.     
    {

        

  21.     
        switch (mmc->status) {

        

  22.     
            case MMC_STATUS_DISCONNECTED:

        

  23.     
                return 0;

        

  24.     
     

        

  25.     
            /* attempt reconnect of sockets in unknown state */

        

  26.     
            case MMC_STATUS_UNKNOWN:

        

  27.     
                mmc->status = MMC_STATUS_DISCONNECTED;

        

  28.     
                return 0;

        

  29.     
        }

        

  30.     
     

        

  31.     
        mmc_server_deactivate(mmc TSRMLS_CC);

        

  32.     
        return 1;

        

  33.     
    }

        

在这里,我们发现,如果store失败的话,下面会有一个容错处理,通过php -i | grep memcache 可以看到容错配置确实是打开的。
在容错的代码中明显发现做了断开连接的操作,但是在哪里重连的呢? 

这要看mmc_hash_find_server的实现了,有时间再看。。。

 Posted by at 上午 7:53
12月 102009
 

官方地址: http://code.google.com/p/memcacheq/

安装方法在INSTALL里面都说的很明白了,这里就絮叨一下自己安装时遇到的一些问题。

1. 文档中说bdb依赖为: Berkeley DB 4.7 or later; 于是我就下了一个最新的4.8.24, 结果安装时不会自动找4.8版本的,还是找4.7版本的,可能通过修改一些问题可以搞定,但是也没有必要,就重新下了一个4.7版本的,安装很顺利了; 所以说,严格安装文档来安装吧!

2. 启动时忘记指定user了,虽然我将错误做了重定向,但是错误信息还是写到了/dev/null中了,这应该算是一个bug吧。

3. 因为memcacheq的数据时落地的,所以要通过-H参数指定数据存放的路径用以存放数据,且该目录要对指定的user可写

 Posted by at 上午 3:42
10月 132009
 

我是经常使用nc来查看mc的状态的,突然有一天,我使用nc命令做set操作,发现总是失败;用telnet没有问题,至少应该不是memcached的问题,可能是nc的问题吧。

今天又遇到了这个问题,我使用tcpdump观察使用nc和使用telnet的差别,发现nc发送的回车为\n ,而telnet发送的回车符为\r\n,差异就这么多了,于是使用下列命令测试:

echo -e "set a 0 0 1\r\na\r\nquit\r\n"|nc host port
结果成功

echo -e "set a 0 0 1\na\nquit\n"|nc host port
结果失败

比较久可以知道问题是出现在回车符上了,至于memcached是怎么解释的,有时间在了解一下源码吧

 Posted by at 上午 12:14
10月 112009
 

1. 对于已经运行着的memcached,如果要在里面存放其他的东西,需要注意这item的大小是否和原来存放的item的大小相当,如果不相当,同时memcached的内存已经开辟完了,则无法开辟新的空间给新的item使用,因为开辟出去的内存是不会自动回收的。

2. 尽量不要使用set来删除内容,使用set方法删除的item是不会优先使用的,只有内存都开辟完了才会使用,所以使用set来删除的话,内存开辟的很快的,你将不知道有多少内存是有效利用的

 Posted by at 下午 8:11
8月 182009
 

本文是一个查看mc的PHP脚本文件,用法简单。

 

 Posted by at 上午 6:36
6月 082009
 

我们知道memcache的PHP客户端在连接mc后,如果中间memcached宕掉了,你们重启之后,mc-client会自动连接到server的,这是如何做到的呢?

先写一个test脚本:

<?php
$mc
= new Memcache
();
$mc->connect("10.10.10.10",11211
);

while(1){
$ret = $mc->set("a","a"
);
if(
$ret
) {
echo
"okn"
;
} else {
echo
"failn"
;
}
sleep(1
);
}

?>

启动脚本后,先宕掉memcached,再启动memcached:

                                   间隔时间
第一次失败的时间: 1240491343.709920
第一次重连:      1240491358.751046 15s
第二次重连:      1240491373.790693 15s
第三次重连:      1240491388.829329 15s
第四次重连:      1240491403.869810 15s

结论: mc client 失败后,如果没有主动重连,在15s后再使用该连接,将尝试重连,在15s内根本就不做尝试重连的动作,即使服务器15s内
又恢复正常服务,mc client也是不知道的

——————————————-

关于pconnect的研究:

先写一个test脚本:

<?php
$mc
= new Memcache();
while(
1){
$mc->pconnect("10.55.38.18",11211);
$ret = $mc->set("a","a");
if(
$ret) {
echo
"okn";
} else {
echo
"failn";
}
sleep(1);
}
?>

1. 虽然pconnect是针对apache类程序开发的,但是命令行程序里有相同的效果
2. 虽然$mc->pconnect("10.55.38.18",11211);是写在了循环里面,但是通过tcpdump发现,并没有每次都重连mc
3. 虽然好像每次都重连,其实都还是完全有connect里的机制来控制了,就是说循环里面的pconnect与写到循环外面没有任何的区别
4. 如果把里面的pconnect 换成connect,则效果就和我们想象的一样了,这样,不管服务器端是否有异常,每次都是真正的连接

程序在$mc->pconnect("10.55.38.18",11211);时报的两种错误:
第一种:Warning: Memcache::pconnect(): Can’t connect to 10.55.38.18:11211, Unknown error (0) in /usr/home/junjie2/testmc.php on line 4

第二种:PHP Warning:  Memcache::pconnect(): Can’t connect to 10.55.38.18:11211, Connection refused (111) in /usr/home/junjie2/testmc.php on line 4

前者是因为并没有真正去连接,只是发现连接不可用(已关闭)就直接返回错误了
后者是第一次失败的15s之后,就尝试做一次真正的重新连接,因为这是memcached还没有重启,就返回了 Connection refused,这样下次pconnect,又接着返回第一种错误,直到又过15s

php的memcahce-2.2.4 中文件 php_memcache.h 中有如下定义

#define MMC_DEFAULT_RETRY 15                             /* retry failed server after x seconds */

即:  15s内是不做真正的连接的。

注意: memcache客户端默认设置的超时时间为1s, 极容易超时的,所以你要知道,当超时后,客户端会主动关闭连接的,因为它以为服务器down了,然后就是15s内的操作统统返回失败。

如何避免这种问题呢?

办法一: 在第一个测试脚本中,使用了connect,而不是pconnect, 连接操作是在循环体外的;如果connect(注意不是pconnect)发生在循环体内就能及时发现连接已有效了,就不需要等待15s了,当然,这样的话,每次都是真实的重新连接了,而且特别需要注意的是,如果这样的话,close()操作也一定要写在循环体里面,否则你将创建n多连接,知道不允许你在连接了。

办法二: 使用addServer的方式: bool Memcache::addServer     ( string $host    [, int $port = 11211    [, bool $persistent    [, int $weight    [, int $timeout    [, int $retry_interval    [, bool $status    [, callback $failure_callback    [, int $timeoutms   ]]]]]]]] )

    将$retry_interva 设置为0,这样就每次都重新连接了。


 Posted by at 上午 7:20
3月 102009
 

使用mc时,我们会考虑数据的存储格式;php的函数允许我们直接set一个数组到mc里,取出来后也可以直接当做数组来用,确实很简单,但是和json格式比较了一下才发现,简单的代价是浪费了更大的空间,下面是一个小的测试程序:

<?php
$host 
"10.10.10.10"
;
$port "11211"
;

$uid "103630";
$p1 
= array(
    
"et"=>"103630"
// expire time
    
"pt"=>"103630"
//
    
"pv"=>"103630"
,
    
"ut"=>"103630"
,
    
"st"=>"103630"
,
    
"pp"=>"103630"
,
    
"s"=>"103630"
,
    
"ot"=>
"103630"

);
$data[] = $p1
;
$mc = new Memcache
();
$mc->connect($host,$port
);
$mc->set(103631,$data
);
$mc->set(103632,json_encode($data
));
?>

telnet 10.10.10.10 11211
get 103631
VALUE 103631 1 191
a:1:{i:0;a:8:{s:2:"et";s:6:"103630";s:2:"pt";s:6:"103630";s:2:"pv";s:6:"103630";s:2:"ut";s:6:"103630";s:2:"st";s:6:"103630";s:2:"pp";s:6:"103630";s:1:"s";s:6:"103630";s:2:"ot";s:6:"103630";}}
END
get 103632
VALUE 103632 0 114
[{"et":"103630","pt":"103630","pv":"103630","ut":"103630","st":"103630","pp":"103630","s":"103630","ot":"103630"}]
END

可见json还是比较节省内存空间的。

 Posted by at 上午 7:53