Memcached последовательное хеширование, не работающее с 3 из 4 серверов вниз

История

У меня есть 3 сервера memcached, где я завершаю ту или иную работу, чтобы исследовать поведение PHP-memcached на сервере, не достижимом.

Я определил 4 сервера в PHP, 1, чтобы имитировать сервер, который в основном отключен (запасной сервер). Когда я завершаю 1 сервер (= > 2, все еще в сети), третий ->get() дает мне результат.

Когда я завершаю работу еще одного сервера (= > 1, все еще в сети), он не найдет объекты, которые были перенесены на этот последний сервер.

Образец вывода

Первый запуск, 3 из 4 серверов вверх:

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

Второй запуск, 3 из 4 серверов вверх:

Entity found in Cache: SUCCESS

Третий запуск, 2 из 4 серверов вверх:

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

Четвертый запуск, 1 из 4 серверов вверх:

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 каждый раз, когда он не находит в кеше, он больше не может найти ключ.

Я думаю, что он также должен работать только с одним сервером.

Можете ли вы объяснить мне это поведение?

Похоже, что невозможно реализовать что-то, что является безопасным даже при отключении 19 из 20 серверов.

Sidequestion: libketama на самом деле больше не поддерживается, хорошо ли это использовать? Логика lib была довольно хорошей и также используется на сервере кэширования лаков.

Приложение

Мой Script:

<?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;

Ответ 1

  • Поведение, которое вы испытываете, является последовательным. Когда сервер недоступен, он сначала помечен как сбой, а затем помечен как мертвый.

Проблема заключается в том, что, по-видимому, это было бы только согласованным, если бы вы установили значение Memcached::OPT_SERVER_FAILURE_LIMIT равным 2, в то время как вы установили его равным 1. Это объясняло бы, почему у вас есть две строки ошибок на один недоступный сервер (CONNECTION FAILURE, SERVER IS MARKED AS DEAD)

Это, похоже, связано с таймаутом. Добавление usleep() после сбоя с соответствующим значением OPT_RETRY_TIMEOUT позволит удалить сервер из списка (см. следующий комментарий об ошибке)

  • Значение не реплицируется на следующий сервер, так как распределяются только ключи.

  • Обратите внимание, что OPT_LIBKETAMA_COMPATIBLE не использует libketama, но воспроизводит только тот же алгоритм, что означает, что не имеет значения, если libketama больше не активен, в то время как это рекомендуемая конфигурация в документации PHP:

Настоятельно рекомендуется включить эту опцию, если вы хотите использовать согласованное хеширование, и оно может быть включено по умолчанию в будущих выпусках.

EDIT: В моем понимании вашего сообщения сообщение "Entity, найденное в Cache: SUCCESS" появляется только во втором запуске (1 сервер в автономном режиме), потому что нет изменений в предыдущей команде, и сервер, на котором размещен этот ключ, все еще доступен (так memcached рассмотрит из ключ, что значение хранится на 1-м, 2-м или 3-м сервере). Позвольте назвать эти серверы Джоном, Джорджем, Ринго и Павлом.

В третьем прогоне, при запуске, memcached выводит из ключа, которому принадлежит один из четырех серверов (например, Джон). Он спрашивает Джона дважды, прежде чем сдаться, потому что теперь он выключен. Его алгоритм учитывает только 3 сервера (не зная, что Пол уже мертв) и выводит, что Джордж должен содержать значение.

Джордж дважды отвечает, что он не содержит значения, а затем сохраняет его.

Но в четвертой перспективе Джон, Джордж и Пол ушли. Мемкейч дважды пробует Джона, а затем дважды пытается Джорджа. Затем он хранится в Ринго.

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

Ответ 2

Избыточность

Так как 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