php - framework - tutorial django
¿Cómo eliminar elementos con la misma clave de prefijo en memcached? (4)
¿Qué tal esta función en PHP:
function deletekeysbyindex($prefix) {
$m = new Memcached();
$m->addServer(''localhost'', 11211);
$keys = $m->getAllKeys();
foreach ($keys as $index => $key) {
if (strpos($key,$prefix) !== 0) {
unset($keys[$index]);
} else {
$m->delete($key);
}
}
return $keys;
}
Borra las claves que comienzan con $ prefijo y devuelve una lista de todas las claves eliminadas. Ejecuté esto con más de 30,000 claves ahora en un servidor compartido y fue bastante rápido, probablemente menos de un segundo.
Por ejemplo, tengo algunos elementos en caché con el mismo prefijo, como
''app_111111'', ''app_222222'', ''app_333333'', ...
¿Puedo eliminar dichos elementos ''app_xxxxxx'' con cualquier comando de memcached?
Este es un hack que funciona, aunque un poco lento. En un servidor con 0,6 millones de claves, tardó medio segundo en completarse.
$prefix = ''MyApp::Test'';
$len = strlen($prefix);
$proc = popen(''/usr/local/bin/memdump --servers=localhost'', ''r'');
while (($key = fgets($proc)) !== false) {
if (substr_compare($key, $prefix, 0, $len) === 0) {
$memcached->delete(substr($key, 0, -1));
}
}
Memcached no ofrece esta funcionalidad de manera inmediata, por lo que debe crearla usted mismo.
La forma en que resuelvo esto es mediante la definición de un prefijo (o espacio de nombres) en mi aplicación para grupos de claves. Cualquier clave que establezca en memcached tiene ese prefijo antes. Cada vez que quiero "borrar" cosas de Memcached, simplemente cambio el prefijo. Y cada vez que quiero buscar una clave en Memcached, le agrego ese prefijo.
En su caso, puede comenzar configurando el prefijo a, por ejemplo, MyAppPrefix1
, de modo que sus claves se almacenarán como MyAppPrefix1::app_333333
, MyAppPrefix1::app_444444
.
Más adelante, cuando desee "eliminar" estas entradas, configure su aplicación para que use MyAppPrefix2
. Luego, cuando intente obtener una clave de Memcached llamada app_333333
, buscará MyAppPrefix2::app_333333
y no la encontrará la primera vez, como si se hubiera eliminado.
No podemos hacer eso en una sola solicitud a memcache. Solo podemos hacer esto:
public function clearByPrefix($prefixes = array()) {
$prefixes = array_unique($prefixes);
$slabs = $this->memcache->getExtendedStats(''slabs'');
foreach ($slabs as $serverSlabs) {
if ($serverSlabs) {
foreach ($serverSlabs as $slabId => $slabMeta) {
if (is_int($slabId)) {
try {
$cacheDump = $this->memcache->getExtendedStats(''cachedump'', (int) $slabId, 1000);
} catch (Exception $e) {
continue;
}
if (is_array($cacheDump)) {
foreach ($cacheDump as $dump) {
if (is_array($dump)) {
foreach ($dump as $key => $value) {
$clearFlag = false;
// Check key has prefix or not
foreach ($prefixes as $prefix) {
$clearFlag = $clearFlag || preg_match(''/^'' . preg_quote($prefix, ''/'') . ''/'', $key);
}
// Clear cache
if ($clearFlag) {
$this->clear($key);
}
}
}
}
}
}
}
}
}
}
Y llama a esta función así:
$prefixes = array();
array_push($prefixes, ''prefix1_'');
array_push($prefixes, ''prefix2_'');
array_push($prefixes, ''prefix3_'');
$this->clearByPrefix($prefixes);