Lorsque plusieurs processus ou threads essaient de lire les manquements de cache et d'écrire dans le cache en même temps, plusieurs processus peuvent exécuter la même requête lente ou des calculs complexes en même temps, ce qui entraîne un gaspillage de ressources. Cette situation est appelée condition de race de cache.
Par exemple:
if (!apcu_exists('my_cache_key')) {
$data = get_data_from_db(); // Requête complexe
apcu_store('my_cache_key', $data);
}
echo apcu_fetch('my_cache_key');
Dans un environnement de concurrence élevé, plusieurs demandes constatent que le cache n'existe pas en même temps et que les requêtes de base de données seront exécutées en même temps, causant des problèmes de performance.
Le nom complet d' APCU_CAS est "Comparez et échangez", qui est une opération atomique utilisée pour comparer si la valeur mise en cache est égale à la valeur attendue, et si elle est égale, elle sera remplacée par une nouvelle valeur. Cette opération peut éviter le problème de concurrence causée par plusieurs demandes pour modifier le cache simultanément.
Prototype de fonction:
bool apcu_cas(string $key, mixed $old, mixed $new)
$ clé : clé de cache
$ old : la valeur ancienne attendue
$ nouveau : la nouvelle valeur à remplacer
Le rendement vrai signifie que le remplacement est réussi, faux signifie que l'ancienne valeur ne correspond pas et le remplacement est en panne.
Nous implémentons le cache d'accès Mutex en définissant un drapeau "verrouillage". Idées spécifiques:
Lisez le cache et retournez directement s'il existe.
Si le cache n'existe pas, essayez de définir un drapeau "verrouillage" pour indiquer que le cache est généré.
La définition du "verrouillage" a échoué, indiquant que d'autres processus génèrent déjà du cache, attendent ou réessayent.
Une fois le paramètre réussi, exécutez une requête lente pour générer des données.
Écrivez des données sur le cache et relâchez l'indicateur "Lock".
Retourner les données.
function getCacheData() {
$cacheKey = 'my_cache_key';
$lockKey = 'my_cache_key_lock';
// 1. Essayez d'abord de lire le cache
$data = apcu_fetch($cacheKey, $success);
if ($success) {
return $data;
}
// 2. Essayer de passerapcu_casSe verrouiller,Empêcher plusieurs demandes de générer simultanément des caches
// 先尝试Se verrouiller标志位为false(Statut initial)
apcu_add($lockKey, false);
// Le verrouillage attendu estfalse,Essayez de changertrue(Verrouillage)
if (!apcu_cas($lockKey, false, true)) {
// Indique que d'autres demandes ont été verrouillées,Attendez la génération de cache
// Peut être simplesleepOu attendez dans une boucle
usleep(100000); // attendez100millisecondes
return getCacheData(); // Essayer récursivement
}
// 3. Obtenir le verrouillage,Exécuter une requête lente
$data = get_data_from_db();
// 4. Écrire du cache
apcu_store($cacheKey, $data);
// 5. Relâchez le verrouillage(Se verrouiller为false)
apcu_store($lockKey, false);
return $data;
}
function get_data_from_db() {
// Simuler la requête lente
sleep(1);
return ['time' => time(), 'data' => 'sample'];
}
Dans le code ci-dessus, APCU_CAS garantit la commutation atomique de "Lock", évite plusieurs demandes d'exécution des requêtes lentes en même temps et évite la concurrence de cache.
Les conditions de race de mise en cache sont un problème courant dans les scénarios de mise en cache à forte concurrence.
APCU_CAS est un outil puissant pour implémenter les opérations atomiques et peut réaliser un mécanisme de verrouillage efficace.
Grâce au mécanisme "Lock", il est assuré qu'une seule demande peut effectuer une requête lente et écrire du cache, et d'autres demandes peuvent attendre ou réessayer.
Cette méthode convient au cache APCU dans des environnements autonomes, et des solutions de verrouillage plus complexes peuvent être prises en compte dans des environnements distribués.
La maîtrise de l'utilisation d' APCU_CAS peut rendre votre mécanisme de cache PHP plus robuste et efficace, évitant de manière significative les goulots d'étranglement des performances causés par la rupture du cache.
$data = apcu_fetch($cacheKey, $success);
if ($success) {
return $data;
}
apcu_add($lockKey, false);
if (!apcu_cas($lockKey, false, true)) {
usleep(100000);
return getCacheData();
}
$data = get_data_from_db();
apcu_store($cacheKey, $data);
apcu_store($lockKey, false);
return $data;
}
fonction get_data_from_db () {
sommeil (1);
return ['time' => time (), 'data' => 'échantillon'];
}
?>
</code>