Согласованное хеширование в 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 серверов.

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

Мой сценарий:

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

11

Решение

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

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

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

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

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

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

РЕДАКТИРОВАТЬ:
Насколько я понимаю ваш пост, сообщение «Объект, найденный в кэше: УСПЕХ» появляется только при втором запуске (1 сервер в автономном режиме), потому что нет изменений по сравнению с предыдущей командой, и сервер, на котором размещен этот ключ, все еще доступен (поэтому memcached рассматривает из ключ, который хранится на 1-м, 2-м или 3-м сервере). Давайте назовем эти серверы Джоном, Джорджем, Ринго и Полом.

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

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

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

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

5

Другие решения

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

Начиная с 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

0