6月 252014
 

 

缘起

如何让PHP memcached client在失败一次后立即进入下次使用依然尝试连接?

测试脚本:

 

 Posted by at 下午 6:13
6月 232014
 

脚本如下:

 

bool Memcache::addServer ( string $host [, int $port = 11211 [, bool $persistent [, int$weight [, int $timeout [, int $retry_interval [, bool $status [, callable$failure_callback [, int $timeoutms ]]]]]]]] )

其中:

对于$retry_interval:

-1 : 对于失败的server不做retry

0:对于失败的server每次都retry

n(>0): 对于失败的server间隔n 秒后会retry一次

 

对于callback

当容错策略启用后,返回错误时并不会触发callback的调用

官方说明:

 Posted by at 下午 8:11
9月 302011
 

前面文章提到,memcache连接失败后,15s内不会重新连接而直接返回连接失败,该问题可以通过使用addServer来指定该时间,本次修改提供了另外一种办法,即:添加ini配置,允许通过ini配置来指定该时间;修改内容如下:

php_memcache.h

memcache.c:

下面几处可以参看源码:
memcache-2.2.6.2.tar.gz

 Posted by at 上午 12:15
8月 022011
 

patch原因:

解决get、delete方法无法区分连接失败和not found的问题

patch内容

本次修改是在memcache-2.2.6 的基础上修改的,我把她修改版本号为 2.2.6.1来使用了,

patch 文件:

patch说明

修改的地方如下:

1. 添加参数检查(memcache.c), 在 ZEND_DECLARE_MODULE_GLOBALS(memcache) 下面添加:


 

2. 修改memcache_get、memcache_delete函数的定义:


 

3. 修改memcache_get 函数的实现:


 

4. 修改delete函数的实现:


 

这里的error_flag 是新添加的可选参数,与改变量相关的地方都是新添加的

 

测试脚本:

 

 

遗留问题

===========================
如果没有第一部分的修改,貌似也是可以的,但是下面三段脚本是值得思考的:


 

 

 Posted by at 上午 10:26
7月 302011
 

前面有篇文章(http://phpor.net/blog/post/883/)提到了PHP 的memcache模块的delete方法的问题,并且做了一些修改,但是,那篇文章也提到,那种修改办法也有很大的缺点,这里给出一种比较好一些的方式。

修改memcache_delete函数如下:

 

测试:

 

输出结果:
should no found:        no found
should ok:      OK
should connect error:   connect error
should key error:       Key in unvalidate
it can work without flag argument, that’s ok
====================================================

本次所学
1. 关于参数的传递,可以直接解析成内部类型,也可以直接使用zval类型
2. 关于引用传参这里做的不太对,且看后面的文章

 Posted by at 上午 6:18
7月 272011
 

【 可直接参看: http://phpor.net/blog/post/888 】

上篇文章解决了PHP的Memcache 模块的get方法不区分连接失败NOT FOUND, 今天说一下delete方法不区分NOT FOUND和连接失败的处理办法。

这次的修改不同上次,虽然delete也有第二个参数,但是第二个参数不是引用(当然可以修改成引用,只是稍微麻烦一点);根据delete的特点,不妨将返回值修改为整型(long型); 代码如下:
==== memcache.c =======

  1. PHP_FUNCTION(memcache_delete)
  2. {
  3.     if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
  4.         RETURN_LONG(-1); // 此处修改
  5.     }
  6.     if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) {
  7.         RETURN_LONG(-1);  // 此处修改
  8.     }
  9.     while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) {
  10.         if ((result = mmc_delete(mmc, key_tmp, key_tmp_len, time TSRMLS_CC)) < 0) {
  11.             mmc_server_failure(mmc TSRMLS_CC);
  12.         }      
  13.     }
  14.     if (result > 0) {
  15.         RETURN_LONG(1); // delete OK
  16.     } elseif(result == 0) {
  17.         RETURN_LONG(0); // not found
  18.     }
  19.     RETURN_LONG(-1); // connect fail
  20. }

测试代码如下:

  1. <?php
  2. $m = new Memcache();
  3. $m->addServer(“127.0.0.1”, 11211); // this is available
  4. $result = $m->delete(“noexists”);
  5. var_dump($result);
  6. $m->set(“exists”,“I am here”,0,600);
  7. $result = $m->delete(“exists”);
  8. var_dump($result);
  9. $m = new Memcache();
  10. $m->addServer(“127.0.0.1”, 11214); // this is available
  11. $result = $m->delete(“noexists”);
  12. var_dump($result);

输出:
int(0)
int(1)
int(-1)

这样修改以后,确实挺好用的,但是,和原来的用法已经不兼容了,除非你原来根本就不判断返回值。

 Posted by at 上午 8:07
7月 262011
 

缘起

PHP连接Memcached一般有两个模块可以使用: libmemcached和memcache;
libmemcached是不支持PHP的长连接的,但是这个模块对各种错误的处理支持的比较好,如果不要求长连接的话,一般使用该模块。
memcache模块自从我开始使用(3年前)用的是2.2.4版本,到现在stable才到2.2.6; 开发极慢,而且最为让人诟病的一个bug就是: get($key)的返回值对于连接失败和NOT FOUND都是返回false的,以至于我无法知道究竟是哪种错误;如果我不关心二者的区别也就算了,对于必须(或者非常有必要)区别二者的话,只好选择使用libmemcached了。

现在遇到的问题是: 我既要区分连接失败和NOT FOUND,我有需要使用长连接,只好去看memcache的源码了。

解决办法

【可直接参看: http://phpor.net/blog/post/888 】

对于memcache的get方法有第二个参数,这个很少使用(而且用的时候也很是不爽的),就是flag参数,该参数为引用传递,旨在回传memcache中的存储标识,而且比较常用的标识就只有几个(如:压缩);看了一下源码,不妨通过该参数来回传失败的类型,如果是NOT FOUND,则可以将该参数设置一个特殊的标识,具体修改代码如下:

==== memcache.c ===

  1. int mmc_exec_retrieval_cmd(mmc_pool_t *pool, const char *key, int key_len, 
  2.         zval **return_value, zval *return_flags TSRMLS_DC) /* {{{ */
  3. {
  4.     mmc_t *mmc;
  5.     char *command, *value; 
  6.         /* not found */
  7.             if (result == 0) { 
  8.                 flags |= 1<<30;
  9.                 ZVAL_FALSE(*return_value);
  10.             }
  11. }

下面是一个测试脚本:

  1. <?php
  2. $m = new Memcache();
  3. $m->addServer(“127.0.0.1”, 11211); // this is available
  4. //$m->addServer(“127.0.0.1”, 11219); //this is unavailable
  5. define(“E_MC_NO_FOUND”, 1<<30); 
  6. $flag=0;  // 这个一定要有值,否则是不会回传$flag的,大概这是一个bug吧
  7. $result = $m->get(“noexists”,$flag);
  8. if($result === false) {
  9.     if ($flag & E_MC_NO_FOUND) {
  10.         echo “not found\n”;
  11.     } else {
  12.         echo “connect error\n”;
  13.     }
  14. }
  15. echo “flag:”.decbin($flag);

遗留问题:
为什么$flag 不设置一个值就不能回传内部的值,究竟源码错在了何处?

 Posted by at 上午 9:50
4月 132011
 

Memcached 1.4.5里面通过sasl提供了认证支持,编译的时候可以启用该功能,编译参数:
[memcached-1.4.5]# ./configure –help| grep -i sasl
  –enable-sasl           Enable SASL authentication
  –enable-sasl-pwdb      Enable plaintext password db

SASL全称Simple Authentication and Security Layer,是一种用来扩充C/S模式验证能力的机制;

关于sasl:
参考文档:http://tools.ietf.org/html/rfc4422
c库实现: http://asg.web.cmu.edu/sasl/sasl-library.html
GNU libgsasl实现: http://www.gnu.org/software/gsasl/
其它资料:
http://asg.web.cmu.edu/sasl/

 Posted by at 上午 12:51