PHP - Memcached - Libmemcached - Обработка сбоев сервера кеша

Я работаю над тем, чтобы наше приложение изящно ухудшалось в случае полного сбоя кеша, что маловероятно, поскольку у нас есть минимум 3 узла кеша для добавления в пул кеша с помощью PHP memcached addServer вызов API. Тем не менее, возможно, что один узел может выйти из строя, и мне нужно убедиться, что memcached api правильно обрабатывает этот сценарий.

Вот мой текущий конфиг cache.yml

port: 11211
<?php echo Hobis_Api_Cache::TYPE_VOLATILE; ?>:
  options:
    - <?php echo Memcached::OPT_CONNECT_TIMEOUT; ?>: 25<?php echo PHP_EOL; ?>
    #- <?php echo Memcached::OPT_DISTRIBUTION; ?>: <?php echo Memcached::DISTRIBUTION_CONSISTENT; ?><?php echo PHP_EOL; ?>
    - <?php echo Memcached::OPT_LIBKETAMA_COMPATIBLE; ?>: true<?php echo PHP_EOL; ?>
    - <?php echo Memcached::OPT_NO_BLOCK; ?>: true<?php echo PHP_EOL; ?>
    #- <?php echo Memcached::OPT_POLL_TIMEOUT; ?>: 100<?php echo PHP_EOL; ?>
    #- <?php echo Memcached::OPT_RECV_TIMEOUT; ?>: 10000<?php echo PHP_EOL; ?>
    - <?php echo Memcached::OPT_REMOVE_FAILED_SERVERS; ?>: true<?php echo PHP_EOL; ?>
    - <?php echo Memcached::OPT_RETRY_TIMEOUT; ?>: 1<?php echo PHP_EOL; ?>
    #- <?php echo Memcached::OPT_SEND_TIMEOUT; ?>: 10000<?php echo PHP_EOL; ?>
    - <?php echo Memcached::OPT_SERIALIZER; ?>: <?php echo Memcached::SERIALIZER_IGBINARY; ?><?php echo PHP_EOL; ?>
    #- <?php echo Memcached::OPT_SERVER_FAILURE_LIMIT; ?>: 1<?php echo PHP_EOL; ?>
    - <?php echo Memcached::OPT_TCP_NODELAY; ?>: true<?php echo PHP_EOL; ?>
  servers:
    - vcache-1
    - vcache-2
    - vcache-3
<?php echo Hobis_Api_Cache::TYPE_PERSISTENT; ?>:
  servers:
    - pcache-1

Основываясь на некоторых исследованиях ( здесь и здесь), возможно, что memcached api изящно справится с отключением одного узла, если он является частью пула. Однако в моем случае я не могу написать конкретные ключи во время тестирования. Вместо этого я получаю сообщение об ошибке "невозможно написать" с resultCode 35, который согласно комментариямMEMCACHED_SERVER_MARKED_DEAD,

Я хотел бы, чтобы сервер был помечен как мертвый, потому что я остановил vcache-2/3, и только vcache-1 работает, однако OPT_LIBKETAMA_COMPATIBLE вариант, у меня сложилось впечатление, что memcached api должен записать ключ на другой сервер в пуле. И это с OPT_REMOVE_FAILED_SERVERS вариант, я не должен видеть отмеченные мертвые коды результата, потому что сервер должен быть удален из пула.

Какие-либо предложения?

1 ответ

Решение

Наконец, у меня есть рабочее решение, и я делюсь им с другими на случай, если они столкнутся с одной и той же проблемой. Основой для моего решения послужил этот пост, как только я увидел $testInstance а также $realInstance меня осенило, используйте тестовый экземпляр, чтобы определить, какие серверы доступны, затем добавьте известные действующие серверы в реальный экземпляр. Вы можете спросить себя, почему бы просто не позвонить addServers дважды против одного и того же экземпляра, ответ? Ты не можешь

Если вы попробуете позвонить addServers более одного раза в одном и том же экземпляре вы должны увидеть неожиданное поведение, для меня это был плохой шлюз из-за: "восходящее преждевременно закрытое соединение при чтении заголовка ответа из восходящего потока". Таким образом, был какой-то внутренний механизм, приводящий к сбою PHP, хотя я не знаю, почему конкретно, так как в журнале ошибок не было ошибок.

Вместо того чтобы делать явные вызовы подключения, как сделал автор, я решил использовать доступные getStats() позвони и проверь за пид.

Рабочий фрагмент:

$cacheReal = new Memcached;
$cacheTest = new Memcached;

if (count($cacheTest->getServerList()) < 1) {

    $knownGoodServers   = array();
    $serversToAdd       = array();

    foreach ($servers as $server) {             
        $serversToAdd[] = array($server, $port);
    }

    $cacheTest->addServers($serversToAdd);

    foreach ($cacheTest->getStats() as $server => $stats) {

        // Test if server is actually available
        if ((false === Hobis_Api_Array_Package::populatedKey('pid', $stats)) ||
            ($stats['pid'] < 0)) {
            continue;
        }

        $knownGoodServers[] = $server;
    }

    // It is possible that entire cache pool took a dump
    if (true === Hobis_Api_Array_Package::populated($knownGoodServers)) {

        $serversToAdd = array();

        foreach ($knownGoodServers as $server) {

            list($host, $port) = array_map('trim', explode(':', $server));

            $serversToAdd[] = array($host, (int) $port);
        }

        if (true === Hobis_Api_Array_Package::populated($serversToAdd)) {
            $cacheReal->addServers($serversToAdd);
        }
    }
}

В моем тестировании у меня было несколько узлов кеша, которые все работали для теста 1, затем для последующих тестов я включал и выключал некоторые узлы кеша, и, наконец, все выключал (для проверки ухудшения). Единственным заметным отличием было то, что после отключения узла или добавления узла обратно (с помощью перезапуска демона) мой сеанс, вошедший в систему, будет завершен, что имеет смысл, поскольку кэшированные данные больше не доступны на ожидаемом сервере. Однако последующие запросы после повторного входа продемонстрировали ожидаемое поведение при входе в систему, поскольку данные сеанса были записаны в узлы кэша, доступные во время запроса.

Другие вопросы по тегам