Accueil Blog Mettre en cache ou ne pas mettre en cache ?

Mettre en cache ou ne pas mettre en cache ?

Stéphane Bélanger | 2 décembre 2022

SURTURE

Cacher ou ne pas cacher, telle est la question :
S'il est utile à l'esprit de souffrir
Les frondes et les ah-rows de l'attente scandaleuse,
Ou de prendre les armes contre une mer de rangs
Et en s'opposant les cache. Mourir, dormir, ou pas.

Mettre en cache ou ne pas mettre en cache ?

VUE D'ENSEMBLE

Je suis fasciné par les caches depuis le milieu des années 2000, lorsque je travaillais sur un gros projet de middleware qui souffrait d'une interface utilisateur insupportable à cause d'un pilote ODBC très lent. C'était bien sûr avant l'avènement des applications en nuage. La solution trouvée consistait à introduire une couche de cache dans le middleware, entre l'application client et le serveur de base de données. Nous sommes passés d'un temps de réponse de plusieurs secondes à des dizaines de millisecondes, soit une amélioration au centuple. Le cache utilisé (ehcache) et le logiciel intermédiaire qui l'utilise sont encore utilisés aujourd'hui.

Lorsque je parle de mise en cache, je ne fais pas référence à l'utilisation normale de PXCache utilisée dans les graphiques, mais plutôt au mécanisme de mise en cache dit " Slot" qui se trouve dans la classe PX.Data.PXDatabase. Si vous parlez à certains développeurs, beaucoup vous diront "ne faites jamais ça" ou "ce n'est pas recommandé". Je ne suis pas d'accord avec ces affirmations, d'autant plus que le code Acumatica prêt à l'emploi utilise beaucoup de ces stratégies de mise en cache. C'est encore plus souvent le cas avec l'utilisation du PXSelectorAttribute.

CE QU'IL FAUT METTRE EN CACHE ET CE QU'IL NE FAUT PAS METTRE EN CACHE

Avant d'envisager la mise en cache des données, il est important de savoir s'il est approprié de le faire ou non. Les lignes de données ne sont pas toutes identiques. Nous allons donc voir ce qu'elles sont et si elles sont de bonnes candidates à la mise en cache. Voici quelques types de données auxquels nous pourrions penser :

Mettre en cache ou ne pas mettre en cache ?

RAISONS DE METTRE EN CACHE

  • Les données sont souvent nécessaires et ne changent pas beaucoup
  • Un petit sous-ensemble de champs est nécessaire pour toutes les lignes d'un grand tableau.
  • Une grande liste de classes (types) est recherchée dans la liste des assemblages et ne changera pas après le démarrage du système. Par exemple : la liste des PXGraphes ou la liste des processeurs implémentant une interface particulière.
  • Pas d'accès facile à un graphique ou trop coûteux pour lire les données
  • Lorsque plusieurs lectures sont nécessaires pour trouver une correspondance appropriée (sur la base d'une cartographie multi-champs)
  • Lorsque de petits ensembles de données sont nécessaires dans le cadre d'un traitement à haut débit à la milliseconde.

CADRE B2B/EDI

Au cours du développement d'un cadre B2B/EDI pour l'un de nos clients Acumatica, nous avons fini par trouver de nombreux domaines appropriés qui bénéficieraient de la mise en cache. Le cadre que nous avons développé est utilisé pour synchroniser des données et des documents à partir de sources externes vers Acumatica ou vice versa. Il utilise de nombreuses données de configuration qui, une fois configurées, ne changeront probablement pas pendant longtemps. L'approche que nous avons adoptée nous a permis de créer de nombreux petits processeurs de messages/données, tous appelés dans une séquence donnée, et ces nombreux processeurs sont généralement spécialisés dans une chose et une seule, un peu comme les chefs dans une cuisine, où l'un est responsable des grillades, l'autre de la sauce, un autre des salades, un autre des pâtisseries, un autre de la découpe de la viande, etc. Les processeurs sont sans état et sont installés (en utilisant la découverte de Reflection) pendant la publication de la personnalisation et sont liés à une petite ligne de configuration. Dans le contexte du traitement des messages, nous utilisons également de nombreux mécanismes de transformation et de conversion des données qui sont tous configurables par l'utilisateur.

Compte tenu du volume considérable de transactions et de transformations, nous avions besoin d'un moyen d'appeler ces processeurs/conversions en succession rapide sans avoir à supporter le coût des requêtes de la base de données. En outre, pour les définitions des modèles de messages sortants, nous devions extraire les différentes tables et champs utilisés par les graphiques du système pour nous permettre de les lire rapidement afin de générer un modèle de message sortant, qui est le principal moteur des transactions sortantes.

LE MÉCANISME DE LA FENTE

Dans ce cas, le mécanisme de mise en cache est celui de la classe PX.Data.PXDatabase. Quelle est la particularité du mécanisme de mise en cache des créneaux :

  • Stocke vos données dans des dictionnaires sécurisés
  • Sstocke les données en fonction de la clé que vous avez définie, ce qui vous permet de restreindre l'accès à vos données mises en cache.
  • Peut stocker et extraire des données de manière sélective à l'aide d'un paramètre (une classe/un type pour représenter et accéder à un sous-ensemble de données).
  • Stockage des données par entreprise (chaque entreprise a son propre cache)
  • Appelle automatiquement un délégué Prefetch lors du premier accès aux données mises en cache
  • Surveille automatiquement les tables dépendantes (que vous configurez) et réinitialise le cache lorsque quelqu'un a mis à jour l'une des tables dépendantes.
  • Gère automatiquement le mode cluster (utilisation de tables dépendantes à travers les clusters).

Examinons les différentes méthodes utilisées dans ce cas précis dans notre code :

GIST : https://gist.github.com/ste-bel/45a9e58f89054a70a76520137e825322

TABLES CONCERNÉES

Dans la section suivante, nous examinerons certaines des tables impliquées dans la mise en cache du B2B Framework.

Mettre en cache ou ne pas mettre en cache ?

LE CODE

Un POCO pour stocker/organiser mes données

First, I create a POCO to store my cached data.  Acumatica does not recommend creating constructors in DACs and they are quite heavy in nature.  Therefore, I prefer to use my own lightweight POCOs.  I also implement IEquatable<> and override GetHashCode() so that my searches are more efficient.

GIST : https://gist.github.com/ste-bel/cd07f0bc9810b11ead1aafa818606765

Une classe d'aide pour stocker et rechercher des données

Deuxièmement, je crée une classe d'aide pour simplifier le chargement du code et la recherche des données. Je peux également encapsuler et améliorer mon algorithme de recherche sans perturber le reste du code. Vous pouvez considérer ce morceau de code comme un seau de données. Vous pouvez également utiliser une hiérarchie d'aides/de seaux afin d'accélérer les recherches et de réduire votre couplage global avec le code utilisant l'aide initiale.

GIST : https://gist.github.com/ste-bel/26088249b9b584fce94af07631c7393c

Le chargeur de données des créneaux horaires

Le dernier morceau de code consiste à créer une classe implémentant IPrefetchable pour lire les données en utilisant les méthodes de PXDatabase sans avoir besoin d'un graphique. J'utilise également un dictionnaire pour stocker mes helpers/buckets et subdiviser mes données dans ce cas par une clé telle qu'un ConversionID ou un ClassID.

Dans ma méthode Prefetch, je vide mon dictionnaire d'aides, puis je lis les données et je remplis mon dictionnaire avec toutes les aides.

Ensuite, je fournis quelques méthodes statiques pour récupérer les aides par leur ID et j'utilise l'aide pour rechercher des données.

GIST : https://gist.github.com/ste-bel/c3d8a380c88d5ff71fbc6102d4d9539a

L'utilisation du chargeur de données

Pour utiliser le chargeur de données, il suffit de parler à votre chargeur pour obtenir l'aide, puis d'utiliser l'aide pour convertir les données.

GIST : https://gist.github.com/ste-bel/96f6b77a93c14ed8cd70db21b4bfab92

CONCLUSION

Au début, la mise en cache et la récupération des données peuvent sembler un travail considérable. Cependant, une fois que l'on s'y est habitué, on peut réaliser ce type de code en une demi-heure et l'amélioration de la vitesse est considérable. En utilisant les classes Yaql (Yet another Query Language), vous pouvez également lire plus d'une table et utiliser des conditions complexes. 

Voir cette GIST pour plus de détails : https://gist.github.com/ste-bel/a27c51dd4234d88c7d098b161b3d9386

Je vous souhaite bonne chance dans vos efforts de mise en cache et bon codage !

Auteur du blog

La carrière de Stéphane, qui s'étend sur plus de 25 ans, a débuté en tant que développeur ERP sur un langage 4GL appelé Miracle. Après quelques années, il a été envoyé à Philadelphie pour travailler avec Weyerhaeuser pour un contrat de 10 jours qui a duré 4 ans, où il a contribué à la réingénierie des modules Transport et EDI. Il a créé, entre autres, près d'une douzaine de nouvelles transactions EDI. Il s'est ensuite aventuré dans le désert des personnalisations et du middleware Java à la recherche de son Graal ERP. En 2016, il a été engagé par le studio de jeux vidéo Behaviour Interactive où il a sélectionné, implémenté et intégré un ERP avec d'autres applications cloud. Quel ERP ? Acumatica bien sûr. En 2018, il a décidé de revenir à ses racines en tant que développeur ERP et a commencé à travailler pour des partenaires Acumatica Gold de premier plan afin de partager ses connaissances, sa passion et ses idées. Depuis, il n'a cessé d'être heureux.

Recevez les mises à jour du blog dans votre boîte de réception.