Langage de requête d'objet pour le cache distribué

Auteur : Iqbal Khan

NCache vous permet de créer un cache distribué évolutif dans le niveau intermédiaire afin de réduire les déplacements coûteux vers la base de données et d'améliorer considérablement les performances de votre application. Cela améliore également l'évolutivité des applications car vous pouvez trouver des données fréquemment utilisées dans ce cache hautement évolutif au lieu d'un serveur de base de données unique qui ne peut pas très bien évoluer.

Votre application utilise généralement un cache en tant que table de hachage où tout est stocké en fonction d'une clé et vous devez disposer de cette clé pour récupérer un élément. C'est comme avoir une base de données relationnelle où vous ne pouvez utiliser que la clé primaire pour trouver des données. Cela fonctionne bien dans de nombreuses situations, mais dans une application complexe réelle, votre application a souvent besoin de trouver des données basées sur des attributs autres que la clé primaire. Et, puisque vous conservez une grande partie de vos données dans le cache, il serait très utile que vous puissiez également effectuer une recherche dans le cache de cette manière. NCache fournit exactement une telle installation.

Dans cet article, je vais expliquer comment NCache l'interrogation d'objet fonctionne.

Recherche de cache renvoyant des clés

NCache fournit un langage de requête d'objet (OQL) pour vous permettre de rechercher dans le cache. Vous devez effectuer des appels d'API et spécifier une recherche basée sur cet OQL afin d'extraire une collection d'objets du cache. Voici ce que vous devez utiliser dans votre application .NET pour interroger le cache.

public class Program
{
    public static void Main(string[] args)
    {
        NCache.InitializeCache("myReplicatedCache");
        String query = "SELECT NCacheQuerySample.Business.Product WHERE this.ProductID > 100";
        // Fetch the keys matching this search criteria
        ICollection keys = NCache.Cache.Search(query);
        if (keys.Count > 0)
        {
            IEnumerator ie = keys.GetEnumerator();
            while (ie.MoveNext())
            {
                String key = (String)ie.Current;
                Product prod = (Product)NCache.Cache.Get(key);

                HandleProduct(prod);
                Console.WriteLine("ProductID: {0}", prod.ProductID);
            }
        }
        NCache.Cache.Dispose();
    }
} 

Le code ci-dessus recherche le cache et renvoie une collection de clés. Ensuite, il itère sur toutes les clés renvoyées et récupère individuellement les éléments mis en cache correspondants dans le cache. L'avantage de cette approche est que la requête ne renvoie pas automatiquement beaucoup de données et ne renvoie que des clés. Ensuite, l'application cliente peut déterminer les clés qu'elle souhaite récupérer. L'inconvénient de cette approche est que si vous récupérez de toute façon la plupart des éléments du cache, vous finirez par faire de nombreux allers-retours vers le cache. Et, si le cache est distribué, cela peut éventuellement devenir coûteux. Si cela devient le cas, vous pouvez effectuer une recherche qui renvoie les clés et les éléments ensemble.

Recherche de cache renvoyant des éléments

Comme vous l'avez déjà vu, un simple Cache.Search(...) renvoie une collection de clés. Cependant, si vous avez l'intention de récupérer la totalité ou la plupart des éléments mis en cache associés à ces clés, alors Cache.Search(...) n'est pas un moyen très efficace de rechercher dans le cache. La raison en est que vous devrez d'abord passer un appel pour effectuer la recherche. Ensuite, vous effectuerez un certain nombre d'appels pour récupérer les éléments associés à chaque clé. Cela peut devenir une opération très coûteuse. Dans ces situations, il est préférable de récupérer toutes les clés et tous les éléments en un seul appel. Vous trouverez ci-dessous l'exemple faisant exactement cela.

public class Program
{
    public static void Main(string[] args)
    {
        NCache.InitializeCache("myReplicatedCache");
        String query = "SELECT NCacheQuerySample.Business.Product WHERE this.ProductID > 100";
        // Fetch the keys matching this search criteria
        IDictionary dict = NCache.Cache.SearchEntries(query);
        if (dict.Count > 0)
        {
            IDictionaryEnumerator ide = dict.GetEnumerator();
            while (ide.MoveNext())
            {
                String key = (String)ide.Key;
                Product prod = (Product)ide.Value;
                HandleProduct(prod);
                Console.WriteLine("Key = {0}, ProductID: {1}",
                key, prod.ProductID);
            }
        }
        NCache.Cache.Dispose();
    }
}

Le code ci-dessus recherche dans le cache et renvoie un dictionnaire contenant à la fois des clés et des valeurs. De cette façon, toutes les données basées sur les critères de recherche sont récupérées en un seul appel à NCache. C'est un moyen beaucoup plus efficace de récupérer toutes les données du cache que de faire Cache.Search().

Indexation des attributs de recherche

Gardez à l'esprit que NCache exige que tous les attributs interrogeables soient indexés. En effet, sans indexation, NCache devrait parcourir l'intégralité du cache pour trouver les éléments recherchés par l'utilisateur. Et, c'est une opération très coûteuse avec le potentiel de ralentir l'ensemble du cache et d'annuler la principale raison pour laquelle les gens voudraient NCache, notamment pour booster les performances et l'évolutivité de leurs applications.

NCache fournit son propre mécanisme d'indexation. Vous pouvez identifier les objets de vos assemblys .NET que vous souhaitez indexer. Ensuite, lorsque vous ajoutez des données à NCache, il vérifie si vous ajoutez ces objets. Et, si vous l'êtes, il utilise .NET Reflection pour extraire les données des attributs indexés et crée son index interne. Ensuite, lorsque vous interrogez le cache avec Cache.Search() ou Cache.SearchEntries(), NCache utilise ces index pour trouver rapidement les objets recherchés et vous les renvoie.

Indexation des attributs d'objet avant de démarrer le cache
Figure 1 : indexation des attributs d'objet avant de démarrer le cache

Veuillez noter que chaque fois que vous spécifiez des index sur des attributs d'objet, cela augmente un peu le temps de traitement des opérations d'ajout, d'insertion et de suppression. Cependant, l'opération Get n'est pas affectée.

Interrogation de différentes topologies de mise en cache

Bien que le comportement de recherche du point de vue de l'application cliente soit le même, quelles que soient les topologies de mise en cache que vous utilisez, les éléments internes de la recherche varient d'une topologie à l'autre. Par exemple, si vous effectuez une recherche sur un cache répliqué, votre recherche est entièrement effectuée sur le serveur de cache à partir duquel vous avez lancé cette recherche. C'est parce que l'intégralité du cache y est disponible. Voici comment une requête est exécutée dans un cache répliqué.

La requête s'exécute localement sur un serveur
Figure 2 : la requête s'exécute localement sur un serveur

Toutefois, si vous disposez d'une topologie de mise en cache partitionnée ou de réplica partitionné, toutes les données ne résident pas sur un seul nœud de cache dans le cluster. Dans cette situation, le serveur de cache sur lequel la requête est lancée envoie la requête à tous les autres serveurs du cluster et l'exécute également localement. La requête s'exécute ensuite sur tous les serveurs en parallèle et ses résultats sont renvoyés de tous les nœuds vers ce nœud de serveur d'origine. Ce nœud serveur combine alors tous les résultats (fait une "union") et les renvoie au client. Ci-dessous un schéma montrant tout cela.

La requête s'exécute en parallèle sur tous les nœuds de serveur
Figure 3 : La requête s'exécute en parallèle sur tous les nœuds de serveur

Vos assemblages .NET

In NCache, l'indexation est effectuée sur les nœuds du serveur. Cependant, NCache utilise .NET Reflection côté client pour extraire les valeurs des attributs d'objet et les envoie au serveur. Par conséquent, vos assemblys .NET qui contiennent la définition d'objet ne sont requis que du côté client où réside votre application. Que vous exécutiez en mode InProc ou OutProc, vos assemblys doivent se trouver dans un répertoire où votre application cliente peut y accéder.

En outre, NCache prend également en charge le langage de requête objet pour les clients Java.

Syntaxe du langage de requête

NCache prend en charge un langage de type SQL appelé Object Query Language (OQL). Ce langage a la syntaxe suivante dans NCache.

SELECT NCacheQuerySample.Business.Product WHERE this.ProductID > 100;

SELECT NCacheQuerySample.Business.Product WHERE (this.ProductID != 100 AND this.ProductID <= 200);

SELECT NCacheQuerySample.Business.Product WHERE (this.ProductID == 150 OR this.ProductID == 160);

SELECT NCacheQuerySample.Business.Product WHERE this.ProductID IN (1, 4, 7, 10);

SELECT NCacheQuerySample.Business.Product WHERE this.ProductID NOT IN (1, 4, 7, 10);

SELECT NCacheQuerySample.Business.Employee WHERE this.HiringDate > DateTime.now;

SELECT NCacheQuerySample.Business.Employee WHERE this.HiringDate > DateTime ('01/01/2007');

SELECT NCacheQuerySample.Business.Employee WHERE this.Hired = true;

Vous pouvez combiner plusieurs expressions avec AND et OR et en utilisant des parenthèses imbriquées. La grammaire complète de la syntaxe du langage de requête est spécifiée ci-dessous.

<Query>                 ::= SELECT <ObjectType> 
                          | SELECT <ObjectType> WHERE <Expression>

<Expression>            ::= <OrExpr>

<OrExpr>                ::= <OrExpr> 'OR' <AndExpr>
                          | <AndExpr>

<AndExpr>               ::= <AndExpr> 'AND' <UnaryExpr>
                          | <UnaryExpr>

<UnaryExpr>             ::= 'NOT'  <CompareExpr>
                          | <CompareExpr>

<CompareExpr>           ::= <Atrrib> '='  <Value>
                          | <Atrrib> '!=' <Value>
                          | <Atrrib> '==' <Value>
                          | <Atrrib> '<>' <Value>
                          | <Atrrib> '<'  <Value>
                          | <Atrrib> '>'  <Value>
                          | <Atrrib> '<=' <Value>
                          | <Atrrib> '>=' <Value>
                          | <Atrrib> 'IN' <InList>
                          | <Atrrib> 'NOT' 'IN' <InList>
                          | '(' <Expression> ')'

<Atrrib>		::= <ObjectValue>                                                    

<Value>                 ::= '-' <NumLiteral> 
                          | <NumLiteral> 
                          | <StrLiteral>
                          | 'true'
                          | 'false'
                          | <Date>

<Date>                  ::= 'DateTime' '.' 'now'
                          | 'DateTime' '(' StringLiteral ')'

<StrLiteral>		::= StringLiteral
			  | 'null'  

<NumLiteral>            ::= IntegerLiteral 
                          | RealLiteral

<ObjectType>            ::= '*' 
                          | <Property>

<Property>		::= <Property> '.' Identifier
			  | Identifier

<ObjectValue>           ::= Keyword '.' Identifier              

<InList>                ::= '(' <ListType> ')'

<ListType>              ::= <NumLiteralList>
                          | <StrLiteralList>
                          | <DateList>

<NumLiteralList>        ::=  <NumLiteral> ',' <NumLiteralList>
                          | <NumLiteral>

<StrLiteralList>        ::= <StrLiteral> ',' <StrLiteralList>
                          | <StrLiteral>

<DateList>              ::= <Date> ',' <DateList>
                          | <Date> 

Conclusion

Comme vous l'avez vu, NCache rend très simple l'interrogation du cache distribué. Il s'agit d'une fonctionnalité puissante qui vous permet d'utiliser votre cache de manière plus significative et d'y trouver des éléments plus facilement. Vérifiez-le.


Auteur : Iqbal Khan travaille pour Alachisoft , un éditeur de logiciels de premier plan fournissant des solutions de mise en cache distribuée .NET et Java, de mappage O/R et d'optimisation du stockage SharePoint. Vous pouvez le joindre au iqbal@alachisoft.com.

© Copyright Alachisoft 2002 - . Tous droits réservés. NCache est une marque déposée de Diyatech Corp.