我正在努力确保我们的应用程序在caching完全中断的情况下正常降级,这是非常不可能的,因为通过PHP的memcached addServer API调用,至less有3个caching节点添加到caching池。 但是,单个节点可能会失败,我需要确保memcached api正确处理这种情况。
这是我目前的cache.ymlconfiguration
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可以优雅地处理单个节点的中断,如果是池的一部分。 但在我的情况下,我无法在testing过程中编写特定的键。 相反,我得到一个“无法写入”的错误,resultCode为35,根据注释 ,它是MEMCACHED_SERVER_MARKED_DEAD 。
有一个标记为死亡的服务器确实是我所期望的,因为我停止了vcache-2/3,而只有vcache-1正在运行,但是,对于OPT_LIBKETAMA_COMPATIBLE选项,我认为memcached api是写入密钥的池中的另一台服务器。 而那OPT_REMOVE_FAILED_SERVERS选项,我不应该看到标记的死亡结果代码,因为服务器应该从池中删除。
有什么build议么?
最后,我有一个工作的解决scheme,并与他人分享,如果他们遇到相同的缝合。 我的解决scheme的基础来自这篇文章 ,一旦我看到$testInstance和$realInstance它在我身上,使用testing实例来确定哪些服务器可用,然后添加已知的良好的服务器到实际的实例。 你可能会问自己,为什么不直接调用addServers两次对同一个实例,答案呢? 你不能。
如果您尝试addServers调用addServers对同一个实例,您应该会看到意外的行为,对我来说,这是一个错误的网关,因为:“从上游读取响应头时上游过早closures连接”。 所以有一些内部的机制导致PHP失败,虽然我不知道为什么具体,因为没有错误出现在错误日志。
我没有像作者那样做明确的连接调用,而是select使用可用的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); } } }
在我的testing中,我有多个caching节点,都运行testing1,然后为了后续testing,我切换了一些caching节点closures,然后最后都closures(testing降级)。 唯一明显的区别是,在取消节点或添加节点(通过守护程序重新启动)之后,我的login会话将被注销,这是合理的,因为caching的数据在预期的服务器上不再可用。 但是,在login后login后显示预期的行为后续请求,因为会话数据已写入请求时可用的caching节点。