11

故事

我有 3 个 memcached 服务器正在运行,我关闭其中一个或另一个以调查 PHP-memcached 在服务器无法访问时的行为。

我在 PHP 中定义了 4 台服务器,其中 1 台用于模拟大部分离线的服务器(备用服务器)。当我关闭 1 台服务器(=> 2 台仍然在线)时,第三台服务器->get()给了我一个结果。

当我再关闭一台服务器时(=> 1 仍然在线),它不会找到推送到最后一台服务器的对象。

样本输出

首次运行,4 台服务器中的 3 台启动:

Entity not found in cache on 1st try: NOT FOUND
Entity not found in cache on 2nd try: NOT FOUND
Entity not found in cache on 3rd try: NOT FOUND
Entity not found in cache on 4th try: NOT FOUND

第二次运行,4 台服务器中的 3 台启动:

Entity found in Cache: SUCCESS

第三次运行,4 台服务器中的 2 台启动:

Entity not found in cache on 1st try: CONNECTION FAILURE
Entity not found in cache on 2nd try: SERVER IS MARKED DEAD
Entity not found in cache on 3rd try: NOT FOUND
Entity not found in cache on 4th try: NOT FOUND

第四次运行,4 台服务器中的 1 台启动:

Entity not found in cache on 1st try: CONNECTION FAILURE
Entity not found in cache on 2nd try: SERVER IS MARKED DEAD
Entity not found in cache on 3rd try: CONNECTION FAILURE
Entity not found in cache on 4th try: SERVER IS MARKED DEAD

尽管只有一台服务器在线,并且每次在缓存中找不到任何对象时,我都会将对象推送到 memcached,但它不再能够找到密钥。

我认为它也应该只剩下一个服务器。

你能向我解释这种行为吗?

看起来即使我关闭了 20 台服务器中的 19 台,也无法实现安全的东西。

旁白:libketama 真的不再维护了,用它还好吗?lib 背后的逻辑相当不错,并且也用于 varnish 缓存服务器。

附录

我的脚本:

<?php
require_once 'CachableEntity.php';
require_once 'TestEntity.php';

echo PHP_EOL;

$cache = new Memcached();
$cache->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$cache->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$cache->setOption(Memcached::OPT_SERVER_FAILURE_LIMIT, 1);
$cache->setOption(Memcached::OPT_REMOVE_FAILED_SERVERS, true);
$cache->setOption(Memcached::OPT_AUTO_EJECT_HOSTS, true);

$cache->setOption(Memcached::OPT_TCP_NODELAY, true);
//$cache->setOption(Memcached::OPT_RETRY_TIMEOUT, 10);

$cache->addServers([
    ['localhost', '11212'],
    ['localhost', '11213'],
    ['localhost', '11214'],
    ['localhost', '11215'], // always offline
]);


$entityId = '/test/test/article_123456789.test';

$entity = new TestEntity($entityId);

$found = false;

$cacheKey = $entity->getCacheKey();

$cacheResult = $cache->get($cacheKey);
if (empty($cacheResult)) {
    echo 'Entity not found in cache on 1st try: ' . $cache->getResultMessage(), PHP_EOL;
    
    $cacheResult = $cache->get($cacheKey);
    if (empty($cacheResult)) {
        echo 'Entity not found in cache on 2nd try: ' . $cache->getResultMessage(), PHP_EOL;
        
        $cacheResult = $cache->get($cacheKey);
        if (empty($cacheResult)) {
            echo 'Entity not found in cache on 3rd try: ' . $cache->getResultMessage(), PHP_EOL;
            
            $cacheResult = $cache->get($cacheKey);
            if (empty($cacheResult)) {
                echo 'Entity not found in cache on 4th try: ' . $cache->getResultMessage(), PHP_EOL;
                
                $entity
                    ->setTitle('TEST')
                    ->setText('Hellow w0rld. Lorem Orem Rem Em M IpsuM')
                    ->setUrl('http://www.google.com/content-123456789.html');
                
                $cache->set($cacheKey, $entity->serialize(), 120);
            }
        }
        else { $found = true; }
    }
    else { $found = true; }
}
else { $found = true; }


if ($found === true) {
    echo 'Entity found in Cache: ' . $cache->getResultMessage(), PHP_EOL;
    $entity->unserialize($cacheResult);
    echo 'Title: ' . $entity->getTitle(), PHP_EOL;
}

echo PHP_EOL;
4

2 回答 2

5
  • 您正在经历的行为是一致的。当服务器不可用时,它首先被标记为失败,然后被标记为死亡。

问题是,显然只有在将值设置为 1 时将值设置为 2,它才会是连贯Memcached::OPT_SERVER_FAILURE_LIMIT的。这可以解释为什么每个无法访问的服务器有两个错误行 ( CONNECTION FAILURE, SERVER IS MARKED AS DEAD)

这似乎与超时有关。usleep()在失败后添加一个匹配OPT_RETRY_TIMEOUT值将使服务器从列表中删除(请参阅以下错误注释

  • 该值不会复制到下一个服务器,因为仅分发密钥。

  • 请注意,OPT_LIBKETAMA_COMPATIBLE它不使用 libketama,而仅复制相同的算法,这意味着 libketama 不再处于活动状态并不重要,而这是PHP 文档中的推荐配置:

如果您想使用一致的散列,强烈建议启用此选项,并且可能会在未来的版本中默认启用。

编辑: 根据我对您的帖子的理解,消息“在缓存中找到的实体:成功”仅出现在第二次运行(1 个服务器脱机),因为上一个命令没有变化,并且托管此密钥的服务器仍然可用(所以 memcached从键中考虑值存储在第一个、第二个或第三个服务器上)。我们将这些服务器称为 John、George、Ringo 和 Paul。

在第三次运行中,开始时,memcached 从密钥中推断出四个服务器中的哪一个服务器拥有该值(例如 John)。它在放弃之前问了约翰两次,因为它现在已经关闭了。然后它的算法只考虑 3 个服务器(不知道 Paul 已经死了)并推断 George 应该包含该值。

George 两次回答它不包含该值,然后将其存储。

但在第四轮比赛中,约翰、乔治和保罗下场了。Memcached 尝试 John 两次,然后尝试 George 两次。然后它存储在 Ringo。

这里的问题是不可用的服务器在不同的运行之间没有被记忆,并且在同一次运行中你必须在它被删除之前询问两次服务器。

于 2017-12-28T10:45:25.493 回答
0

冗余

从 Memcached 3.0.0 开始,就有了冗余配置。

  • 它可以在扩展配置文件中进行。

/etc/php/7.0/mods-available/memcached.ini(操作系统之间可能不同)

memcache.redundancy=2
  • 与 ini_set('memcache.redundancy', 2)

这个参数没有真正记录,你可以用服务器的数量替换“2”,这会增加额外的写入开销。

失去 19/20 台服务器

有了冗余,您可能会丢失一些服务器并保持“读取成功”。

笔记:

libketama

Github 存储库自 2014 年以来未收到任何提交。Libketama 正在寻找新的维护者https://github.com/RJ/ketama

于 2017-12-24T12:47:40.070 回答