Maison >Java >JavaBase >L'implémentation Java garantit la cohérence de la double écriture entre le cache et la base de données

L'implémentation Java garantit la cohérence de la double écriture entre le cache et la base de données

coldplay.xixi
coldplay.xixiavant
2020-12-30 17:51:022914parcourir

Tutoriel de base Javala colonne assure la cohérence de la double écriture entre cache et base de données

L'implémentation Java garantit la cohérence de la double écriture entre le cache et la base de données

S'il vous plaît, relevez la tête, ma princesse, sinon la couronne tombera.

Le cache distribué est un composant indispensable dans de nombreuses applications distribuées. Cependant, lors de l'utilisation du cache distribué, cela peut impliquer un double stockage et une double écriture du cache et de la base de données. Il y a certainement des problèmes de cohérence des données, alors comment résoudre le problème de cohérence ?

Modèle Cache Aside

Le mode de mise en cache + lecture et écriture de base de données le plus classique est le modèle Cache Aside.
Lors de la lecture, lisez d'abord le cache. S'il n'y a pas de cache, lisez la base de données, puis retirez les données et mettez-les dans le cache, et renvoyez la réponse en même temps.

Lors de la mise à jour, mettez d'abord à jour la base de données, puis supprimez le cache.

Pourquoi supprimer le cache au lieu de mettre à jour le cache ?

La raison est très simple. Dans de nombreux cas, dans des scénarios de mise en cache complexes, le cache n'est pas seulement la valeur extraite directement de la base de données.

Par exemple, un champ d'une certaine table peut être mis à jour, puis le cache correspondant doit interroger les données des deux autres tables et effectuer des opérations pour calculer la dernière valeur du cache.

De plus, le coût de mise à jour du cache est parfois très élevé. Cela signifie-t-il qu'à chaque fois que la base de données est modifiée, le cache correspondant doit être mis à jour ? Cela peut être le cas dans certains scénarios, mais pour les scénarios de calcul de données mises en cache plus complexes, ce n'est pas le cas. Si vous modifiez fréquemment plusieurs tables impliquées dans un cache, le cache sera également mis à jour fréquemment. Mais la question est : ce cache sera-t-il fréquemment consulté ?

Par exemple, si un champ d'une table impliqué dans un cache est modifié 20 fois ou 100 fois en 1 minute, alors le cache sera mis à jour 20 fois ou 100 fois mais ce cache ne sera mis à jour que 20 fois ; fois ou 100 fois en 1 minute. Il a été lu une fois et contient beaucoup de données froides. En fait, si vous supprimez simplement le cache, le cache ne sera recalculé qu'une fois toutes les 1 minute et la surcharge sera considérablement réduite. Le cache n'est utilisé que pour calculer le cache.

En fait, supprimer le cache au lieu de mettre à jour le cache est une idée de calcul paresseuse. Ne refaites pas des calculs complexes à chaque fois, qu'il soit utilisé ou non, mais laissez-le être utilisé quand vous en avez besoin. à utiliser. Recalculez à nouveau. Comme mybatis et hibernate, ils ont tous l'idée du chargement paresseux. Lors de l'interrogation d'un service, le service apporte une liste d'employés. Il n'est pas nécessaire de dire qu'à chaque fois que vous interrogez le service, les données des 1 000 employés qu'il contient seront également trouvées en même temps. Dans 80% des cas, la vérification de ce service nécessite uniquement l'accès aux informations de ce service. Vérifiez d'abord le département, et en même temps vous devez accéder aux employés à l'intérieur. Ensuite, seulement lorsque vous souhaitez accéder aux employés à l'intérieur, vous interrogerez la base de données pour 1 000 employés.

Le problème et la solution d'incohérence du cache le plus élémentaire

Problème : modifiez d'abord la base de données, puis supprimez le cache. Si la suppression du cache échoue, de nouvelles données seront ajoutées dans la base de données et d'anciennes données dans le cache, ce qui entraînera une incohérence des données.
Limplémentation Java garantit la cohérence de la double écriture entre le cache et la base de données

Solution : Supprimez d'abord le cache, puis modifiez la base de données. Si la modification de la base de données échoue, cela signifie qu'il y a d'anciennes données dans la base de données et que le cache est vide, les données ne seront donc pas incohérentes. Comme il n'y a pas de cache lors de la lecture, les anciennes données de la base de données sont lues puis mises à jour dans le cache.

Analyse des problèmes d'incohérence des données plus complexes

Les données ont changé, supprimez d'abord le cache, puis modifiez la base de données, mais elle n'a pas encore été modifiée. Lorsqu'une requête arrive, je lis le cache et constate que le cache est vide. J'interroge la base de données et trouve les anciennes données avant modification et les mets dans le cache. Ensuite, le programme de changement de données termine la modification de la base de données.

C'est fini, les données dans la base de données et dans le cache sont différentes. . .

Pourquoi le cache rencontre-t-il ce problème dans un scénario à forte concurrence avec des centaines de millions de trafic ?

Ce problème ne peut se produire que lorsqu'une donnée est lue et écrite simultanément. En fait, si votre simultanéité est très faible, en particulier si la simultanéité de lecture est très faible, avec seulement 10 000 visites par jour, alors dans de rares cas, le scénario incohérent que nous venons de décrire se produira. Mais le problème est que s'il y a des centaines de millions de trafic chaque jour et des dizaines de milliers de lectures simultanées par seconde, tant qu'il y a des demandes de mise à jour des données chaque seconde, l'incohérence base de données + cache mentionnée ci-dessus peut se produire.

La solution est la suivante :

Lors de la mise à jour des données, acheminez l'opération en fonction de l'identifiant unique des données et envoyez-la vers une file d'attente interne de jvm. Lors de la lecture des données, s'il s'avère que les données ne sont pas dans le cache, les données seront relues + le cache sera mis à jour Après routage selon l'identifiant unique, elles seront également envoyées dans la même file d'attente interne de jvm. .

Une file d'attente correspond à un thread de travail. Chaque thread de travail récupère les opérations correspondantes en série puis les exécute une par une. Dans ce cas, pour une opération de modification de données, le cache est d'abord supprimé puis la base de données est mise à jour, mais la mise à jour n'est pas encore terminée. À ce moment-là, si une demande de lecture arrive et que le cache vide est lu, la demande de mise à jour du cache peut d'abord être envoyée à la file d'attente. À ce moment-là, elle sera en retard dans la file d'attente, puis attendra de manière synchrone que la mise à jour du cache soit effectuée. complété.

Il y a un point d'optimisation ici. Dans une file d'attente, cela n'a aucun sens d'enchaîner plusieurs demandes de mise à jour du cache, donc un filtrage peut être effectué s'il s'avère qu'il y a déjà une demande de mise à jour du cache dans la file d'attente. file d'attente, alors il n'est pas nécessaire d'insérer une autre opération de demande de mise à jour, attendez simplement que la demande d'opération de mise à jour précédente soit terminée.

Une fois que le thread de travail correspondant à cette file d'attente a terminé la modification de la base de données pour l'opération précédente, il effectuera l'opération suivante, qui est l'opération de mise à jour du cache. À ce moment, la dernière valeur sera lue. la base de données, puis écrivez dans le cache.

Si la demande est toujours dans la plage de temps d'attente et qu'une interrogation continue révèle que la valeur peut être obtenue, elle reviendra directement si la demande attend plus d'une certaine période de temps, alors cette fois ; la valeur actuelle sera lue directement à partir de l’ancienne valeur de la base de données.

Dans les scénarios à forte concurrence, les problèmes auxquels il faut prêter attention avec cette solution :

1. Les demandes de lecture sont bloquées pendant une longue période

Parce que les demandes de lecture sont bloquées pendant une longue période. très légèrement asynchrone, nous devons donc faire attention au problème du délai de lecture. Chaque demande de lecture doit être renvoyée dans le délai d'expiration.

Le plus gros point de risque de cette solution est que les données peuvent être mises à jour très fréquemment, ce qui entraîne un important retard dans les opérations de mise à jour dans la file d'attente, puis un grand nombre de délais d'attente se produiront pour les demandes de lecture, et enfin un grand nombre de demandes seront traitées directement dans la base de données. Assurez-vous d'exécuter des tests simulés en situation réelle pour voir à quelle fréquence les données sont mises à jour.

Un autre point, car il peut y avoir un retard dans les opérations de mise à jour pour plusieurs éléments de données dans une file d'attente, vous devez le tester en fonction de vos propres conditions commerciales. Vous devrez peut-être déployer plusieurs services, et chaque service le fera. partager certaines données. Si une file d'attente mémoire compresse réellement les opérations de modification d'inventaire de 100 produits et que chaque opération de modification d'inventaire prend 10 ms, alors la demande de lecture du dernier produit peut attendre 10 * 100 = 1 000 ms = 1 s avant que les données puissent être obtenues. cette fois, cela entraînera un blocage à long terme des demandes de lecture.

Assurez-vous d'effectuer des tests de résistance et de simuler l'environnement en ligne en fonction du fonctionnement réel du système d'entreprise pour voir combien d'opérations de mise à jour peuvent être insérées dans la file d'attente mémoire pendant les périodes les plus chargées, ce qui peut conduire à Comment combien de temps la demande de lecture correspondant à la dernière opération de mise à jour se bloquera-t-elle ? Si la demande de lecture revient dans 200 ms, si vous la calculez, même au moment le plus chargé, il y aura un retard de 10 opérations de mise à jour, et le temps d'attente maximum est de 200 ms, alors ça va.

S'il y a de nombreuses opérations de mise à jour qui peuvent être retardées dans une file d'attente mémoire, vous devez alors ajouter des machines pour permettre aux instances de service déployées sur chaque machine de traiter moins de données que le retard de mises à jour dans chacune. la file d'attente mémoire sera Il y aura moins d'opérations.

En fait, sur la base de l'expérience des projets précédents, d'une manière générale, la fréquence d'écriture des données est très faible, donc en fait, normalement, l'arriéré des opérations de mise à jour dans la file d'attente devrait être très faible. Pour des projets comme celui-ci qui ciblent une concurrence de lecture élevée et une architecture de mise en cache de lecture, d'une manière générale, les demandes d'écriture sont très faibles, et il serait bien que le QPS par seconde puisse atteindre quelques centaines.

Un calcul approximatif est effectivement effectué

S'il y a 500 opérations d'écriture par seconde, et si divisé en 5 tranches de temps, il y aura 100 opérations d'écriture toutes les 200 ms, divisé en 20 Dans la file d'attente mémoire, chaque file d'attente mémoire peut avoir un retard de 5 opérations d'écriture. Après chaque test de performances d'opération d'écriture, il est généralement terminé en 20 ms environ, de sorte que la demande de lecture des données dans chaque file d'attente mémoire ne sera suspendue que pendant un certain temps au maximum et sera définitivement renvoyée dans un délai de 200 ms.

Après le simple calcul de tout à l'heure, nous savons que le QPS d'écriture pris en charge par une seule machine ne pose pas de problème par centaines. Si le QPS d'écriture est multiplié par 10, alors la machine sera étendue, et la machine sera étendue. la machine sera agrandie de 10 fois. Chaque machine compte 20 files d'attente.

2. La simultanéité des demandes de lecture est trop élevée

Un test de résistance doit être effectué ici pour garantir que lorsque la situation ci-dessus se produit, il existe un autre risque, c'est-à-dire un risque important. Un certain nombre de demandes de lecture se produiront soudainement. Le délai de plusieurs dizaines de millisecondes dépend du service et du nombre de machines nécessaires pour gérer le pic de la situation extrême.

Mais comme toutes les données ne sont pas mises à jour en même temps, et que le cache n'expirera pas en même temps, le cache d'un petit nombre de données peut être invalide à chaque fois, et alors les requêtes de lecture correspondant à ces données arrivent simultanément. La quantité ne devrait pas être particulièrement importante.

3. Routage des demandes pour le déploiement d'instances multiservices

Peut-être que ce service déploie plusieurs instances, il faut alors s'assurer que les demandes d'opérations de mise à jour des données et des opérations de mise à jour du cache sont transmises via le serveur Nginx. est acheminé vers la même instance de service.

Par exemple, toutes les requêtes de lecture et d'écriture pour un même produit sont acheminées vers la même machine. Vous pouvez effectuer votre propre routage de hachage entre les services en fonction d'un certain paramètre de requête, ou vous pouvez utiliser la fonction de routage de hachage de Nginx, etc.

4. Le problème de routage des produits chauds entraîne des requêtes asymétriques

Si les requêtes de lecture et d'écriture d'un certain produit sont particulièrement élevées et qu'elles sont toutes envoyées dans la même file d'attente de la même machine, il peut causer La pression sur une certaine machine est trop élevée. C'est-à-dire que parce que le cache ne sera vidé que lorsque les données du produit seront mises à jour, puis une simultanéité de lecture et d'écriture se produira, cela dépend donc en fait du système d'entreprise. Si la fréquence de mise à jour n'est pas trop élevée, l'impact de cela. Le problème n'est pas particulièrement important, mais il est vrai que la charge sur certaines machines peut être plus élevée.

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer