Dan*_* W. 11 php memcached caching consistent-hashing libketama
我有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
Run Code Online (Sandbox Code Playgroud)
第二次运行,4台服务器中的3台:
Entity found in Cache: SUCCESS
Run Code Online (Sandbox Code Playgroud)
第三次运行,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
Run Code Online (Sandbox Code Playgroud)
第四次运行,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
Run Code Online (Sandbox Code Playgroud)
虽然有一台服务器保持在线状态,但每次在缓存中找不到任何服务器时,我都会将对象推送到memcached,因此无法再找到该密钥.
我认为它也应该只用一个服务器.
你能解释一下这种行为吗?
即使我关闭了20个服务器中的19个,看起来也不可能实现安全的东西.
Sidequestion:libketama不再维护了,使用它还是好的吗?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;
Run Code Online (Sandbox Code Playgroud)
问题是,如果您Memcached::OPT_SERVER_FAILURE_LIMIT将此值设置为2,那么显然它只会是连贯的.这可以解释为什么每个无法访问的服务器有两个错误行(CONNECTION FAILURE,SERVER IS MARKED AS DEAD)
这似乎与超时有关.usleep()使用匹配OPT_RETRY_TIMEOUT值添加失败后,将允许从列表中删除服务器(请参阅以下错误注释)
该值不会复制到下一个服务器,因为只分发了密钥.
请注意,OPT_LIBKETAMA_COMPATIBLE不使用libketama,但仅重现相同的算法,这意味着如果libketama不再处于活动状态并不重要,这是PHP文档中的推荐配置:
如果要使用一致性散列,强烈建议启用此选项,并且在将来的版本中可能默认启用它.
编辑: 在我对你的帖子的理解中,消息"在Cache:SUCCESS中找到的实体"只出现在第二次运行(1个服务器离线),因为上一个命令没有变化,托管这个密钥的服务器仍然可用(所以memcached从密钥中考虑该值存储在第一,第二或第三服务器上).我们称这些服务器为John,George,Ringo和Paul.
在第三次运行中,在开始时,memcached从密钥中推断出四个服务器中的哪一个拥有该值(例如John).它在放弃之前要求约翰两次,因为它现在已经关闭了.然后它的算法只考虑3个服务器(不知道Paul已经死了)并推断出George应该包含该值.
乔治回答了两次,因为它不包含值,然后存储它.
但在第四轮比赛中,约翰,乔治和保罗都不在了.Memcached两次尝试John,然后两次尝试George.然后它存储在林戈.
这里的问题是不同的运行之间不存储不可用的服务器,并且在同一运行中,您必须在服务器被删除之前询问两次.