Maison >base de données >Redis >Comment Redis résout-il le problème d'incohérence du cache ?
Cet article vous explique comment Redis résout le problème de l'incohérence du cache et comment se produit l'incohérence des données entre le cache et la base de données. Examinons-le ensemble, j'espère que cela sera utile à tout le monde.
Apprentissage recommandé : Tutoriel d'apprentissage Redis
Tout d'abord, nous devons comprendre ce que signifie spécifiquement « cohérence des données ». En fait, la « cohérence » inclut ici deux situations :
Si ces deux conditions ne sont pas remplies, il s'agit d'un problème d'incohérence des données entre le cache et la base de données. Cependant, lorsque les modes de lecture et d'écriture du cache sont différents, l'apparition d'incohérences des données du cache est différente et nos méthodes de réponse seront également différentes. Par conséquent, nous comprenons d'abord les incohérences du cache dans différents modes en fonction des modes de lecture et d'écriture du cache. Condition. Nous pouvons diviser le cache en cache en lecture-écriture et en cache en lecture seule.
Pour le cache en lecture-écriture, si vous souhaitez ajouter, supprimer ou modifier des données, vous devez le faire dans le cache. En même temps, vous devez décider si vous souhaitez les réécrire dans la base de données de manière synchrone en fonction de l'écriture. stratégie de retour adoptée.
Stratégie d'écriture directe synchrone : lors de l'écriture dans le cache, la base de données est également écrite de manière synchrone, et les données dans le cache et la base de données sont cohérentes ;
Stratégie d'écriture asynchrone : lors de l'écriture dans le cache, la base de données n'est pas écrite de manière synchrone ; , puis réécrit lorsque les données sont éliminées de la base de données cache. Lorsque vous utilisez cette stratégie, si les données n'ont pas été réécrites dans la base de données, le cache échouera et, à ce moment, la base de données ne disposera pas des données les plus récentes.
Donc, pour le cache en lecture-écriture, si vous souhaitez vous assurer que les données du cache et de la base de données sont cohérentes, vous devez adopter une stratégie d'écriture directe synchrone. Cependant, il convient de noter que si vous adoptez cette stratégie, vous devrez mettre à jour le cache et la base de données en même temps. Par conséquent, nous devons utiliser des mécanismes de transaction dans les applications métier pour garantir que les mises à jour du cache et de la base de données sont atomiques, c'est-à-dire qu'elles sont mises à jour ensemble ou qu'aucune des deux n'est mise à jour, qu'un message d'erreur est renvoyé et qu'une nouvelle tentative est effectuée. Sinon, nous ne pouvons pas réaliser une écriture directe synchrone.
Bien sûr, dans certains scénarios, nos exigences en matière de cohérence des données peuvent ne pas être si élevées. Par exemple, si nous mettons en cache les attributs non critiques des produits de commerce électronique ou l'heure de création ou de modification de courtes vidéos, nous pouvons alors les utiliser. écriture asynchrone. Stratégie de retour.
Parlons de la mise en cache en lecture seule. Pour le cache en lecture seule, s'il y a de nouvelles données, elles seront écrites directement dans la base de données ; en cas de suppression de données, les données du cache en lecture seule doivent être marquées comme non valides. De cette manière, lorsque l'application accède ultérieurement à ces données ajoutées, supprimées ou modifiées, un échec de cache se produira car il n'y a pas de données correspondantes dans le cache. À ce stade, l'application lit les données de la base de données dans le cache, de sorte que lors d'un accès ultérieur aux données, elles puissent être lues directement à partir du cache.
Ensuite, prenez comme exemple l'écriture et la suppression de données de Tomcat dans MySQL pour vous expliquer comment les opérations d'ajout, de suppression et de modification de données sont effectuées, comme le montre la figure suivante :
Comme vous pouvez le voir sur la figure, les applications Tomcat exécuté sur la base de données, qu'il s'agisse d'ajouter (opération d'insertion), de modifier (opération de mise à jour) ou de supprimer (opération de suppression) des données X, ajoutera, modifiera et supprimera directement des données dans la base de données. Bien entendu, si l'application effectue une opération de modification ou de suppression, les données X mises en cache seront également supprimées.
Alors, y aura-t-il une incohérence des données dans ce processus ? Étant donné que les situations d'ajout et de suppression de données sont différentes, nous les examinons séparément.
Nous supposons que l'application supprime d'abord le cache, puis met à jour la base de données. Si le cache est supprimé avec succès mais que la mise à jour de la base de données échoue, lorsque l'application accède à nouveau aux données, il n'y aura aucune donnée dans le cache et un un échec de cache se produira. Ensuite, l'application accède à nouveau à la base de données, mais la valeur dans la base de données est l'ancienne valeur et l'application accède à l'ancienne valeur.
Laissez-moi vous donner un exemple. Vous pouvez d'abord regarder la photo ci-dessous
L'application souhaite mettre à jour la valeur des données X de 10 à 3. Elle supprime d'abord la valeur du cache X dans le cache Redis, mais la mise à jour de la base de données échoue. S'il y a d'autres demandes simultanées d'accès
Vous vous demandez peut-être si nous mettons d'abord à jour la base de données, puis supprimons la valeur dans le cache, ce problème peut-il être résolu ? Analysons-le à nouveau.
Si l'application termine d'abord la mise à jour de la base de données, mais échoue lors de la suppression du cache, alors la valeur dans la base de données est la nouvelle valeur et la valeur dans le cache est l'ancienne valeur, ce qui est définitivement incohérent. À ce stade, s'il y a d'autres demandes simultanées pour accéder aux données, selon le processus normal d'accès au cache, le cache sera d'abord interrogé, mais à ce moment, l'ancienne valeur sera lue.
Laissez-moi vous l'expliquer à l'aide d'un exemple.
L'application souhaite mettre à jour la valeur des données X de 10 à 3. Elle met d'abord à jour avec succès la base de données, puis supprime le cache de 3, la valeur en cache de X dans Redis est 10, ce qui est définitivement incohérent . Si un autre client envoie une demande d'accès à X à ce moment-là, il interrogera d'abord Redis. Le client trouvera un accès au cache, mais l'ancienne valeur 10 sera lue.
D'accord, nous pouvons voir ici que lors du processus de mise à jour de la base de données et de suppression des valeurs mises en cache, quel que soit l'ordre dans lequel les deux opérations sont exécutées en premier, tant qu'une opération échoue, le client lira Get the ancienne valeur. J'ai dessiné le tableau ci-dessous pour résumer les deux situations qui viennent d'être évoquées.
Nous connaissons la cause du problème, mais comment le résoudre ?
Tout d'abord, laissez-moi vous présenter une méthode : le mécanisme de nouvelle tentative.
Plus précisément, vous pouvez stocker temporairement la valeur du cache à supprimer ou la valeur de la base de données à mettre à jour dans la file d'attente des messages (par exemple, en utilisant la file d'attente des messages Kafka). Lorsqu'une application ne parvient pas à supprimer les valeurs mises en cache ou à mettre à jour les valeurs de la base de données, elle peut relire les valeurs de la file d'attente des messages et les supprimer ou les mettre à jour à nouveau.
Si nous parvenons à supprimer ou à mettre à jour avec succès, nous supprimerons ces valeursde la file d'attente des messages pour éviter des opérations répétées. À ce stade, nous pouvons également garantir que la base de données et les données mises en cache sont cohérentes. Sinon, nous devons réessayer. Si la nouvelle tentative dépasse un certain nombre de fois et échoue toujours, nous devons envoyer un message d'erreur à la couche métier.
L'image ci-dessous montre que lorsque la base de données est d'abord mise à jour, puis que la valeur du cache est supprimée, si la suppression du cache échoue et que la suppression réussit après une nouvelle tentative, vous pouvez y jeter un œil.
Ce dont je viens de parler, c'est la situation où l'une des opérations échoue lors du processus de mise à jour de la base de données et de suppression des valeurs mises en cache. En fait, même si ces deux opérations n'échouent pas la première fois qu'elles sont exécutées, lorsque. il y a un grand nombre de requêtes simultanées, l'application peut toujours lire des données incohérentes.
De même, nous le divisons en deux situations selon différents ordres de suppression et de mise à jour. Dans les deux cas, nos solutions sont également différentes.
Supposons qu'après que le thread A ait supprimé la valeur du cache, le thread B commence à lire les données avant d'avoir le temps de mettre à jour la base de données (par exemple, il y a un retard réseau). le cache est manquant et ne peut lire qu'à partir de la base de données Pick. Cela entraînera deux problèmes :
Après que le thread B ait lu les données de la base de données et mis à jour le cache, le thread A commence à mettre à jour la base de données. À ce moment, les données dans le cache sont l'ancienne valeur, tandis que les données dans la base de données sont la dernière valeur, et les deux sont incompatibles.
J'utilise un tableau pour résumer cette situation.
Que dois-je faire ? Laissez-moi vous proposer une solution.
Une fois que le thread A a mis à jour la valeur de la base de données, nous pouvons le laisser dormir pendant une courte période, puis effectuer une opération de suppression du cache.
La raison pour laquelle la période de sommeil est ajoutée est de permettre au thread B de lire d'abord les données de la base de données, puis d'écrire les données manquantes dans le cache, puis le thread A les supprime. Par conséquent, le temps nécessaire au thread A pour dormir doit être supérieur au temps nécessaire au thread B pour lire les données, puis les écrire dans le cache. Comment déterminer cette heure ? Il est recommandé de compter le temps de fonctionnement des threads lisant les données et écrivant le cache lorsque le programme métier est en cours d'exécution, et de faire une estimation sur cette base.
De cette façon, lorsque d'autres threads liront des données, ils constateront que le cache est manquant et liront donc la dernière valeur de la base de données. Étant donné que cette solution retardera la suppression pendant un certain temps après la première suppression de la valeur mise en cache, nous l'appelons également « double suppression retardée ».
Le pseudo code suivant est un exemple de solution de "double suppression différée", vous pouvez y jeter un oeil.
redis.delKey(X) db.update(X) Thread.sleep(N) redis.delKey(X)
Scénario 2 : mettez d'abord à jour la valeur de la base de données, puis supprimez la valeur du cache.
Si le thread A supprime la valeur dans la base de données, mais avant d'avoir le temps de supprimer la valeur du cache, le thread B commence à lire les données. À ce moment-là, lorsque le thread B interroge le cache et trouve un accès au cache, il le fera. lire directement les données du cache. Lire l'ancienne valeur. Cependant, dans ce cas, s'il n'y a pas beaucoup de requêtes simultanées émanant d'autres threads pour lire le cache, il n'y aura pas beaucoup de requêtes pour lire l'ancienne valeur. De plus, le thread A supprime généralement très rapidement la valeur mise en cache, de sorte que lorsqu'un autre thread lit à nouveau, un échec de cache se produit et la dernière valeur est lue dans la base de données. Cette situation a donc moins d’impact sur l’entreprise.
Je vais dessiner un autre tableau pour vous montrer la situation de mise à jour de la base de données d'abord, puis de suppression de la valeur mise en cache.
D'accord, nous avons appris ici que l'incohérence des données entre le cache et la base de données est généralement causée par deux raisons, et je vous ai fourni la solution correspondante.
Apprentissage recommandé : Tutoriel vidéo Redis
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!