La compétition de données fait référence à plusieurs processus ou threads qui accédaient aux données partagées en même temps, et au moins un processus ou un thread écrit les données, ce qui entraîne des résultats d'exécution instables du programme ou un comportement imprévisible. En PHP, en particulier lors de l'utilisation du cache APC, car les données en cache sont généralement partagées à l'échelle mondiale, si plusieurs demandes écrivent sur la même clé de cache en même temps, des problèmes de course de données peuvent se produire.
La fonction de la fonction APCU_ENTRY est de vérifier s'il existe déjà des paires de valeurs de clé spécifiées dans le cache. Sinon, il exécute une fonction de rappel pour générer les données et les stocker dans le cache. Dans des circonstances normales, il peut éviter efficacement le problème de calcul en double de l'échec du cache, mais dans des scénarios simultanés, si plusieurs demandes fonctionnent sur la même clé de cache en même temps, les problèmes suivants peuvent être causés:
Calcul répété : lorsque plusieurs demandes sont simultanées, bien que le cache n'atteigne pas, plusieurs demandes peuvent entrer la fonction de rappel en même temps et calculer le même résultat à plusieurs reprises, ce qui entraîne un gaspillage de ressources.
Incohérence : Étant donné que les opérations de cache sont effectuées dans les fonctions de rappel, les opérations simultanées peuvent provoquer un écrasement ou une incohérence des données.
Afin de résoudre le problème de la concurrence des données, l'utilisation d' APCU_ENTRY peut être optimisée de la manière suivante:
Le moyen le plus courant consiste à utiliser un mécanisme de verrouillage pour s'assurer qu'un seul processus peut effectuer des écritures de cache à la fois. Dans PHP, vous pouvez utiliser des verrous de fichiers, redis, memcached, etc. pour implémenter des verrous. Voici une simple implémentation de l'utilisation de verrous de fichiers:
$cache_key = 'my_cache_key';
$lock_key = $cache_key . '_lock';
if (apcu_exists($lock_key)) {
// Si la serrure existe déjà,Attendez un moment et réessayez
sleep(1);
} else {
// Ajouter un verrouillage
apcu_store($lock_key, true, 10); // Le temps d'expiration de verrouillage est10Deuxième
// Générer des valeurs mises en cache
$value = generate_cache_value();
// Stocker des valeurs mises en cache
apcu_store($cache_key, $value);
// Relâchez le verrouillage
apcu_delete($lock_key);
}
En utilisant des verrous, nous pouvons nous assurer qu'en même temps, un seul processus peut entrer dans la logique de rappel générée par le cache, évitant ainsi les calculs répétés.
La fonction APCU_ADD est similaire à la fonction APCU_ENTRY , mais il évite d'écraser les valeurs de cache existantes. Ainsi, lorsque vous avez juste besoin de vous assurer que la clé de cache existe, vous pouvez utiliser APCU_ADD pour réduire les risques de concours de données.
$value = apcu_add('my_cache_key', generate_cache_value(), 3600);
Si la clé de cache existe déjà, APCU_ADD ne l'écrasera pas, réduisant ainsi les conditions de course générées pendant la concurrence.
Un autre moyen simple consiste à vérifier si le cache existe déjà avant d'entrer dans la fonction de rappel, évitez les calculs répétés lorsque plusieurs demandes sont exécutées simultanément. Un drapeau séparé peut être utilisé pour enregistrer si le cache est calculé ou a été calculé. Par exemple:
$cache_key = 'my_cache_key';
if ($result = apcu_fetch($cache_key)) {
// Frappe du cache,Utiliser directement
} else {
// Cache miss,Vérifiez l'état de calcul
$status_key = $cache_key . '_status';
if (!apcu_exists($status_key)) {
// Aucun signe calculé,Marquez comme calculant
apcu_store($status_key, true);
// Effectuer une opération de génération de valeur mise en cache
$result = generate_cache_value();
// Cache de stockage
apcu_store($cache_key, $result);
// Retirez l'indicateur d'état de calcul
apcu_delete($status_key);
} else {
// Attendez les autres demandes pour compléter l'opération de cache
while (!$result = apcu_fetch($cache_key)) {
sleep(1);
}
}
}
De cette façon, lorsque plusieurs demandes fonctionnent sur la même clé de cache en même temps, seule la première demande générera un cache et les demandes restantes attendront la fin de la génération de cache.
Si vos données en cache sont très importantes et ont des exigences élevées pour la cohérence, vous pouvez envisager d'utiliser un mécanisme similaire aux transactions de base de données pour garantir la cohérence des données dans un environnement simultané. Bien que l'APC ne prenne pas directement en charge les transactions, vous pouvez utiliser des transactions de base de données ou des systèmes de mise en cache externes (tels que Redis) pour obtenir des effets similaires.