注意!PHP memcached扩展默认配置下无法自动failover

最近项目中用到PHP连接Memcache的场景。这个场景对于PHP开发者很常见。但就是这么常见的一个场景,带来了意想不到的一个问题。

我这边的php memcached扩展版本是:

memcached

MEMCACHED SUPPORT	 ENABLED
Version	                 2.1.0
libmemcached version	 1.0.8
Session support	         yes
igbinary support	 no
json support	         no

案例如下:
在本地服务器启动两个memcache实例,端口分别为1122,1123。PHP我使用的是MemcacheD扩展(注意,是D)。测试代码如下:

$memcache = new Memcached;

$memcache->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$memcache->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$memcache->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);

$memcache->setOption(Memcached::OPT_TCP_NODELAY, true);
$memcache->setOption(Memcached::OPT_NO_BLOCK, true);
$memcache->setOption(Memcached::OPT_CONNECT_TIMEOUT, 50);
$memcache->setOption(Memcached::OPT_SEND_TIMEOUT, 50);
$memcache->setOption(Memcached::OPT_RECV_TIMEOUT, 50);
$memcache->setOption(Memcached::OPT_POLL_TIMEOUT, 50);
$memcache->setOption(Memcached::OPT_HASH, Memcached::HASH_MD5);

$memcache->addServers(array(array("HOST" => "127.0.0.1", "PORT" => 1122),array("HOST" => "127.0.0.1", "PORT" => 1123));

$mKey = "test_bocheng11";
$status = 2;
$r = $memcache->set($mKey, $status,60*60*24);
$status1 =$memcache->get($mKey);
var_dump($status1);
$memcache->delete($mKey);

然后运行这个脚本。正常情况下可以返回
int(2)

这时候关掉实例1123,再次运行上面的代码,会返回
bool(false)

大家看到这里应该明白出了什么问题,我们上面这段代码无法自动的将fail的server踢出去。这将是一个非常大的隐患。
更麻烦的是,下面这段代码依然无法自动将fail的server去除(使用memcached扩展的默认配置)

$memcache = new Memcached;
$memcache->addServers(array(array("HOST" => "127.0.0.1", "PORT" => 1122),array("HOST" => "127.0.0.1", "PORT" => 1123));

$mKey = "test_bocheng11";
$status = 2;
$r = $memcache->set($mKey, $status,60*60*24);
$status1 =$memcache->get($mKey);
var_dump($status1);
$memcache->delete($mKey);

这段代码中我的key="test_bocheng11"是可以被hash到1122的实例上的,因此我们打开1123实例,关闭1122实例后,会发现返回的是
bool(false)

这个问题最终是看了看libmemcached的源码找到了一个解决方案(我当时的libmemcached的版本是1.0.8,也许高版本的libmemcached已经解决了这个问题)

如下的代码可以解决自动failover的问题?

$memcache = new Memcached;
$memcache->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$memcache->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$memcache->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);

//自动failover配置
/*$memcache->setOption(Memcached::OPT_SERVER_FAILURE_LIMIT, 1);
$memcache->setOption(Memcached::OPT_RETRY_TIMEOUT, 30);
$memcache->setOption(Memcached::OPT_AUTO_EJECT_HOSTS, true);
*/
//最新的libmemcached的文档中可以看到更建议使用如下的选项
$memcache->setOption(Memcached::OPT_REMOVE_FAILED_SERVERS,true);

$memcache->addServers(array(array("HOST" => "127.0.0.1", "PORT" => 1122),array("HOST" => "127.0.0.1", "PORT" => 1123));

$mKey = "test_bocheng11";
$status = 2;
$r = $memcache->set($mKey, $status,60*60*24);
$status1 =$memcache->get($mKey);
var_dump($status1);
$memcache->delete($mKey);

这时只要1122,1123有一个实例正常运行,就可以保证memcache的数据能够存取。
重点是第7--9行的参数设置,但要注意的是,这套参数配置必须配合DISTRIBUTION_CONSISTENT生效,对于memcached扩展默认的DISTRIBUTION_MODULA依然是无法实现failover的。从libmemcached源码中依稀也可以看到一些踪影。

memcached_return_t run_distribution(memcached_st *ptr)
{
  if (ptr->flags.use_sort_hosts)
  {
    sort_hosts(ptr);
  }

  switch (ptr->distribution)
  {
  case MEMCACHED_DISTRIBUTION_CONSISTENT:
  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
  case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
    return update_continuum(ptr);

  case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
  case MEMCACHED_DISTRIBUTION_MODULA:
    break;

  case MEMCACHED_DISTRIBUTION_RANDOM:
    srandom((uint32_t) time(NULL));
    break;

  case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
  default:
    assert_msg(0, "Invalid distribution type passed to run_distribution()");
  }

  return MEMCACHED_SUCCESS;
}

这段代码中可以看到 默认的 MEMCACHED_DISTRIBUTION_MODULA 选项,不会触发 update_continuum 操作,而这个操作会影响到下面这个方法中是否重新选择host的判断

static inline void _regen_for_auto_eject(memcached_st *ptr)
{
  if (_is_auto_eject_host(ptr) && ptr->ketama.next_distribution_rebuild) //这个next_distribution_rebuild值会在update_continuum方法调用时被改变。
  {
    struct timeval now;

    if (gettimeofday(&now, NULL) == 0 and
        now.tv_sec -> ptr->ketama.next_distribution_rebuild)
    {
      run_distribution(ptr);
    }
  }
}

void memcached_autoeject(memcached_st *ptr)
{
  _regen_for_auto_eject(ptr);
}

uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length)
{
  uint32_t hash= _generate_hash_wrapper(ptr, key, key_length);

  _regen_for_auto_eject(ptr);

  return dispatch_host(ptr, hash);
}

update_continuum 部分代码摘要如下,可以看到判断server是否fail以及修改next_distribution_rebuild的部分。

if (is_auto_ejecting)
  {
    live_servers= 0;
    ptr->next_distribution_rebuild= 0;
    for (host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
    {
      if (list[host_index].next_retry <= now.tv_sec)         live_servers++;       else       {         if (ptr->next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->next_distribution_rebuild)
          ptr->next_distribution_rebuild= list[host_index].next_retry;
      }
    }
  }
  else
  {
    live_servers= memcached_server_count(ptr);
  }
时间: 2024-08-03 02:50:49

注意!PHP memcached扩展默认配置下无法自动failover的相关文章

Asp.net 默认配置下,Session莫名丢失的原因及解决办法

Asp.net 默认配置下,Session莫名丢失的原因及解决办法 正常操作情况下Session会无故丢失.因为程序是在不停的被操作,排除Session超时的可能.另外,Session超时时间被设定成60分钟,不会这么快就超时的. 这次到CSDN上搜了一下帖子,发现好多人在讨论这个问题,然后我又google了一下,发现微软网站上也有类似的内容. 现在我就把原因和解决办法写出来. 原因: 由于Asp.net程序是默认配置,所以Web.Config文件中关于Session的设定如下: <sessio

PHP安装memcached扩展笔记

  这篇文章主要介绍了PHP安装memcached扩展笔记,本文讲解了安装服务端.launchpad.安装memcached扩展以及配置PHP.ini等内容,需要的朋友可以参考下 最近在服务器上部缓存系统,记录一下PHP安装memcached扩展. 代码如下: # 安装服务端 yum install memcached -y I. launchpad 请于https://launchpad.net/libmemcached/+download下载目前最新版的libmemcached(201505

Redis 对比 Memcached 并在 CentOS 下进行安装配置详解_Redis

Redis 是一个开源.支持网络.基于内存.键值对的 Key-Value 数据库,本篇文章主要介绍了Redis 对比 Memcached 并在 CentOS 下进行安装配置详解,有兴趣的可以了解一下. 了解一下 Redis Redis 是一个开源.支持网络.基于内存.键值对的 Key-Value 数据库,使用 ANSI C 编写,并提供多种语言的 API ,它几乎没有上手难度,只需要几分钟我们就能完成安装工作,并让它开始与应用程序顺畅协作.换句话来说,只需投入一小部分时间与精力,大家就能获得立竿

Spring和Struts2配置文件不在默认路径下的web.xml配置方法

        希望越大,失望越大.朋友遇到struts2配置文件未在默认路径下的web.xml问题,我帮忙解决了很久,也没有从根本上解决.后来经过看struts2的api,仔细琢磨,最终解决了.给正在学习路上的朋友们一下帮助.         看看我项目中配置文件的原本位置         在看看我web.xml的配置         主要看看struts2的配置文件,为什么要加上struts-default.xml和struts-plugin.xml呢.看api的大致意思是说,默认情况下,这

如何在Crunchbang下恢复Openbox的默认配置

如何在Crunchbang下恢复Openbox的默认配置 CrunchBang是一个很好地融合了速度.风格和内容的基于Debian GNU/Linux的发行版.使用了灵活的Openbox窗口管理器,高度定制化并且提供了一个现代.全功能的GNU/Linux系统而没有牺牲性能. Crunchbang是高度自定义的,用户可以尽情地地把它调整成他们想要的样子.这一切都通过文本文件(配置).我作为一个Crunchbang用户,我最近搞乱了我的menu.xml配置文件,它负责下面的菜单显示. 我的菜单配置文

Ubuntu OpenSSH服务的默认配置和高级设置

介绍 这篇指南由浅入深的介绍属于标准http://www.aliyun.com/zixun/aggregation/13835.html">Ubuntu OpenSSH服务的默认配置和高级设置.这篇文章将详细论述server-side(服务器端)配置指导,并解释了利用Rivest Shamir Adleman (RSA) 算法(注1)生成密钥登陆 OpenSSH 服务器与明文密码的区别.附加的资源为OpenSSH 索引在指南部分. 适当的设定这篇文章里的参数 ,读者应该是一个善于使用命令行

php memcached 扩展 timeout 问题

php 中使用memcached扩展来访问memcached时,当memcached服务器无法正常连接,在默认设置下会造成请求响应变慢.注意:无法正常连接指网络故障,如两台服务器无法进行通信等,只要能ping通,就算memcached服务没有开启或down掉,不会影响响应时间,只是memcached没有启作用. 设置timeout时间通过常量Memcached::OPT_CONNECT_TIMEOUT来控制,默认是4000毫秒(php 官网显示1000,我测试版本1.0.2和2.0.1都是400

memcache与memcached扩展的区别

一.服务端 之前理解错误了.服务端只有一个memcache,一般把服务端称作memcached(带d),是因为守护进程的名称就是叫做memcached(一个这样的执行程序文件).   编写的语言:c语言 官网为:http://memcached.org/    二.客户端   很多人都面对两个php的扩展大有疑惑,而且也记不住,只是知道memcached扩展更加高级嘛. 其实,我觉得,只要了解c语言的两个库的区别,就能知道了本质区别了. 既然要操作服务端,那么就要有客户端来操作.memcache

浅谈blogcms系统默认情况下的seo优化方法

任何一个程序都不可能尽善尽美,而博客系统默认情况下的seo效果也没有完全发挥出来,笔者的博客地址原来是在主域名的一个子目录里,因为子目录或二级域名的自然权重排名没有优势,所以无奈之下把博客迁移到了主域名之下这也增加了网站运营成本,无形中也加大了后期的维护管理工作,所谓有的放矢想要有给力的排名必须是要付出才能有所回报的.很多核心重点工作第一步如果没有确立一个标准那么在后续工作中那是相当纠结的一件事,李正seo顾问提醒诸位上线一个网站之前一定必须先制定好关键性的网站结构,否则在产生排名之后想要改动那