Memcached for PHP和故障转移

时间:2012-09-11 14:28:29

标签: php memcached

我们正在为我们的应用程序部署memcached,我想尽可能地让它变得耐用。

我们计划使用较新的memcacheD扩展程序。

我还没想到的一件事是,如果其中一台服务器死机会发生什么。至少看起来memcached客户端只是“放弃”在该服务器上,并且不会在其中存储任何内容。

这种行为我很好。我们可以处理一堆缓存未命中。但是,如果其中一台服务器被认为“失败”后续集合并被重新分配给剩余的服务器,那将是很好的。

因为这似乎不会自动发生;我想解决这个问题的唯一方法是让外部系统对memcached系统进行健康检查,并适当更新服务器列表。

但是,如果有一个包含10个服务器的列表,并且让我们说,第5个死了......即使使用Ketama-hashing,这似乎会触发重新分配密钥(这只是基于常识)。 / p>

理想情况下,我只是想让PHP扩展程序找出服务器已关闭,将其标记为指定的时间(10分钟),并在这10分钟内回退到其他服务器(很好地分发)设置和获取。

其他人如何解决这个问题?

编辑:澄清我的libketama点。

假设我们有10台服务器:

1,2,3,4,5,6,7,8,9,10

其中一人死亡。然后,Libketama将提供一个非常高的可能性,即丢失的服务器的命中率平均分配给剩余的服务器:

1,2,3,4,inactive,6,7,8,9,10

但是:如果我们手动提供和管理此列表,则情况并非如此:

1,2,3,4,6,7,8,9,10 // There are now 9 servers!

6现在将获得5个以前的密钥,7个将获得6个。 8将获得7,9将获得8,10将获得9。第10台服务器过去获得的所有命中都不会均匀分布在其余服务器中。导致几乎50%的密钥被发送到新服务器的可能性很高。

4 个答案:

答案 0 :(得分:3)

我通常在APC中存储可用服务器列表,因此我可以动态修改它。你是正确的,因为系统会在列出它时尝试继续使用down服务器,幸运的是,使用新的散列方法从旋转中拉出它并不是什么大问题。

我会避免使用全新的PHP扩展,或尝试将新软件添加到您的部署堆栈中。您可能已经在使用某些东西进行监控(nagios?)。让它在你的每个web服务器上调用一个简单的PHP脚本来调整内存列表似乎是最好的选择。

值得注意的是,在Ketama hashing system下,从轮换中移除服务器将导致其密钥在环上的其他位置(连续)重新散列,其他服务器将无法看到别处分配的钥匙。将其可视化为圆形,为每个服务器分配圆上的多个点(100-200)。将键散列到圆圈并顺时针继续,直到找到服务器。从环中删除服务器只会导致这些值继续进一步查找新服务器。幸运的是,值的分配将平等地击中剩余的服务器。

演示散列系统:

<?php


$m = new Memcached();
$m->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);


$m->addServer('localhost', 11211);
$m->addServer('localhost', 11212);
$m->addServer('localhost', 11213);
$m->addServer('localhost', 11214);
$m->addServer('localhost', 11215);
$m->addServer('localhost', 11216);
$m->addServer('localhost', 11217);
$m->addServer('localhost', 11218);
$m->addServer('localhost', 11219);
$m->addServer('localhost', 11210);

$key = uniqid(); //You may change this to md5(uniqid()); if you'd like to see a greater variation in keys. I don't think it necessary.
$m->set($key, $key, 5);


var_dump($m->get($key));

unset($m);


$m = new Memcached();
$m->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
//one server removed. If assignment to the continuum is dependent based on add order, we would expect the get call here to fail 90% of the time, as there will only be a success if the value was stored on the first server. If the assignment is based on some hash of the server details we'd expect success 90% of the time. 
$m->addServer('localhost', 11211);
//$m->addServer('localhost', 11212);
$m->addServer('localhost', 11213);
$m->addServer('localhost', 11214);
$m->addServer('localhost', 11215);
$m->addServer('localhost', 11216);
$m->addServer('localhost', 11217);
$m->addServer('localhost', 11218);
$m->addServer('localhost', 11219);
$m->addServer('localhost', 11210);

var_dump($m->get($key));

unset($m);

$m = new Memcached();
$m->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
//2 servers removed
$m->addServer('localhost', 11211);
$m->addServer('localhost', 11212);
//$m->addServer('localhost', 11213);
//$m->addServer('localhost', 11214);
$m->addServer('localhost', 11215);
$m->addServer('localhost', 11216);
$m->addServer('localhost', 11217);
$m->addServer('localhost', 11218);
$m->addServer('localhost', 11219);
$m->addServer('localhost', 11210);

var_dump($m->get($key));

unset($m);

$m = new Memcached();
$m->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
//Out of order
$m->addServer('localhost', 11210);
$m->addServer('localhost', 11211);
$m->addServer('localhost', 11219);
$m->addServer('localhost', 11212);
$m->addServer('localhost', 11217);
$m->addServer('localhost', 11214);
$m->addServer('localhost', 11215);
$m->addServer('localhost', 11216);
$m->addServer('localhost', 11218);
$m->addServer('localhost', 11219);
$m->addServer('localhost', 11213);

var_dump($m->get($key));

unset($m);

如果散列系统关心订单或省略服务器,我们希望在大多数辅助示例上获得bool(false),因为早期服务器已被删除等等。但是基于我快速,完全非科学的测试,我只在10中的任何一个特定插槽中得到一个bool false。我显然只是在我的测试盒上启动了10个服务器。给每个人只有4mb的公羊

答案 1 :(得分:2)

您可能想尝试PHP的Memcached::OPT_AUTO_EJECT_HOSTS选项常量。它没有直接记录,但有一条评论here命名它。

(我没试过,所以我不能告诉你它是否有效)

答案 2 :(得分:0)

根据评论的答案,我会建议:

您需要构建一个缓存类。

此课程将包含以下信息:

  • 缓存服务器列表

    • 在线或离线状态
    • 对此服务器的请求计数
  • 当前存储的密钥列表及其所在的服务器

接下来,您需要使用标准功能来添加,更新和删除密钥。

每次执行其中一个功能时,您都需要检查密钥是否已经在缓存中以及它所在的服务器上。

如果它不在服务器中,请在检索实际数据库值后选择保存最少请求的服务器。

如果这些函数中的任何一个从缓存服务器返回错误,我会将该服务器标记为脱机,重置计数,并从列表中删除此服务器上的所有密钥。

此时,您可以轻松地将它们自动移动到新服务器或只删除它们,以便再次查询它们。

答案 3 :(得分:0)

我的2美分: 为Memcached开发一个强大的HA模块并不容易。例如,考虑以下情况:

  • 您如何确定哪个服务器还活着哪个服务器死了?您应该以某种方式在运行Web / app服务器的所有HA模块之间进行同步
  • 如何在您的网络/应用服务器之间发布此信息
  • 你打算有一个协调员吗?

我建议您查看现在处于测试阶段的Redis Sentinel,并在过去几个月内开发并测试,专门用于解决Redis中的这些问题。在开始开发一行代码之前,你必须在那里找到许多必须注意的角落案例。

至于此处讨论的其他问题:

  • 当您丢失节点时,您将丢失1 / N的密钥,其中N是您最初拥有的节点数,即包括故障节点。这就是Ketama的工作方式
  • 使用新的Memcached类在Memcached客户端上存储密钥绝对不是可行的方法(IMO):( 1_你要在哪里保存所有这些密钥?(2)你如何在你的web / app节点之间进行同步?(3)您需要多长时间才能访问这些数据结构以了解每个密钥所在的节点? - 这就是为什么Memcached完全基于哈希函数,使其快速而简单。

最后但同样重要的是,我建议你也检查一下Memcached作为服务解决方案。例如,我们Garantia Data已经解决了Memcached的HA问题。

披露:我是Garantia Data的联合创始人兼首席技术官。