Я работаю над тем, чтобы наше приложение плавно деградировало в случае полного отключения кеша, что маловероятно, поскольку у нас есть минимум 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
На основании некоторых исследований (Вот и Вот), api memcached может корректно обрабатывать отказ одного узла, если он является частью пула. Однако в моем случае я не могу писать конкретные ключи во время тестирования. Вместо этого я получаю сообщение об ошибке «Невозможно записать» с кодом результата 35, который, согласно Комментарии, является MEMCACHED_SERVER_MARKED_DEAD
.
Я ожидал, что сервер будет помечен как мертвый, так как я остановил vcache-2/3 и работает только vcache-1, однако OPT_LIBKETAMA_COMPATIBLE
вариант, у меня сложилось впечатление, что memcached api должен записать ключ на другой сервер в пуле. И это с OPT_REMOVE_FAILED_SERVERS
вариант, я не должен видеть отмеченные мертвые коды результатов, потому что сервер должен быть удален из пула.
Какие-либо предложения?
Наконец, у меня есть рабочее решение, и я делюсь им с другими на случай, если они столкнутся с той же проблемой. Основа моего решения пришла из этого Почта, как только я увидел $testInstance
и $realInstance
меня осенило, используйте тестовый экземпляр, чтобы определить, какие серверы доступны, а затем добавить известные хорошие серверы к реальному экземпляру. Вы можете спросить себя, почему бы просто не позвонить addServers
дважды против одного и того же экземпляра, ответ? Вы не можете.
Если вы попробуете позвонить addServers
более одного раза в отношении одного и того же экземпляра вы должны увидеть неожиданное поведение, для меня это был плохой шлюз из-за: «восходящее преждевременно закрытое соединение при чтении заголовка ответа из восходящего потока». Таким образом, был какой-то внутренний механизм, вызывающий сбой PHP, хотя я не знаю, почему конкретно, поскольку в журнале ошибок не было обнаружено ошибок.
Вместо того, чтобы делать явные вызовы подключения, как это сделал автор, я решил использовать доступные getStats()
позвони и проверь pid.
Рабочий фрагмент:
$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, затем для последующих тестов я выключал и включал некоторые узлы кеша, а затем, наконец, все выключал (для проверки деградации). Единственная заметная разница заключалась в том, что после отключения узла или добавления узла обратно (через перезапуск демона) мой сеанс, вошедший в систему, будет отключен, что имеет смысл, поскольку кэшированные данные больше не доступны на ожидаемом сервере. Однако последующие запросы после повторного входа в систему продемонстрировали ожидаемое поведение во время входа в систему, поскольку данные сеанса были записаны в узлы кеша, доступные на момент запроса.