Objektabfragesprache für verteilten Cache

Autor: Iqbal Khan

NCache können Sie einen skalierbaren verteilten Cache in der mittleren Ebene erstellen, sodass Sie teure Zugriffe auf die Datenbank reduzieren und Ihre Anwendungsleistung erheblich verbessern können. Es verbessert auch die Anwendungsskalierbarkeit, da Sie häufig verwendete Daten in diesem hochskalierbaren Cache finden können, anstatt in einem einzelnen Datenbankserver, der nicht sehr gut skaliert werden kann.

Ihre Anwendung verwendet normalerweise einen Cache als Hashtable, in dem alles basierend auf einem Schlüssel gespeichert wird, und Sie müssen diesen Schlüssel haben, um ein Element abzurufen. Dies ist wie eine relationale Datenbank, in der Sie nur den Primärschlüssel verwenden können, um Daten zu finden. Dies funktioniert in vielen Situationen gut, aber in einer realen komplexen Anwendung muss Ihre Anwendung häufig Daten finden, die auf anderen Attributen als dem Primärschlüssel basieren. Und da Sie viele Ihrer Daten im Cache aufbewahren, wäre es sehr nützlich, wenn Sie den Cache auch auf diese Weise durchsuchen könnten. NCache bietet genau diese Möglichkeit.

In diesem Artikel werde ich diskutieren, wie NCache Objektabfrage funktioniert.

Cache-Suche, die Schlüssel zurückgibt

NCache stellt eine Object Query Language (OQL) bereit, mit der Sie den Cache durchsuchen können. Sie müssen API-Aufrufe durchführen und eine Suche basierend auf dieser OQL angeben, um eine Sammlung von Objekten aus dem Cache abzurufen. Folgendes müssen Sie in Ihrer .NET-Anwendung verwenden, um den Cache abzufragen.

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();
    }
} 

Der obige Code durchsucht den Cache und gibt eine Sammlung von Schlüsseln zurück. Dann iteriert es über alle zurückgegebenen Schlüssel und ruft die entsprechenden zwischengespeicherten Elemente einzeln aus dem Cache ab. Der Vorteil dieses Ansatzes besteht darin, dass die Abfrage nicht automatisch viele Daten zurückgibt, sondern nur Schlüssel zurückgibt. Dann kann die Clientanwendung bestimmen, welche Schlüssel sie abrufen möchte. Der Nachteil dieses Ansatzes besteht darin, dass Sie, wenn Sie die meisten Elemente sowieso aus dem Cache holen, am Ende viele Fahrten zum Cache unternehmen werden. Und wenn der Cache verteilt wird, kann dies schließlich kostspielig werden. Wenn dies der Fall ist, können Sie eine Suche durchführen, die die Schlüssel und die Gegenstände zusammen zurückgibt.

Cache-Suche, die Elemente zurückgibt

Wie Sie bereits gesehen haben, gibt ein einfacher Cache.Search(...) eine Sammlung von Schlüsseln zurück. Wenn Sie jedoch alle oder die meisten mit diesen Schlüsseln verknüpften zwischengespeicherten Elemente abrufen möchten, ist Cache.Search(...) keine sehr effiziente Methode zum Durchsuchen des Caches. Der Grund dafür ist, dass Sie zuerst einen Anruf tätigen, um die Suche durchzuführen. Dann führen Sie eine Reihe von Aufrufen durch, um die mit jedem Schlüssel verknüpften Elemente abzurufen. Dies kann eine sehr kostspielige Operation werden. In diesen Situationen ist es besser, alle Schlüssel und Gegenstände in einem Anruf abzuholen. Unten ist das Beispiel, das genau das tut.

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();
    }
}

Der obige Code durchsucht den Cache und gibt ein Wörterbuch zurück, das sowohl Schlüssel als auch Werte enthält. Auf diese Weise werden alle Daten basierend auf den Suchkriterien in einem Aufruf abgerufen NCache. Dies ist eine viel effizientere Methode zum Abrufen aller Daten aus dem Cache als dies zu tun Cache.Search().

Indizierung durchsuchbarer Attribute

Bitte beachten Sie, dass NCache erfordert, dass alle durchsuchbaren Attribute indiziert werden. Denn ohne Indizierung NCache müsste den gesamten Cache durchlaufen, um die Elemente zu finden, nach denen der Benutzer sucht. Und das ist eine sehr kostspielige Operation mit dem Potenzial, den gesamten Cache zu verlangsamen und den Hauptgrund rückgängig zu machen, warum die Leute es tun würden NCache, nämlich um ihre Anwendungsleistung und Skalierbarkeit zu steigern.

NCache bietet einen eigenen Indizierungsmechanismus. Sie können die Objekte in Ihren .NET-Assemblys identifizieren, die Sie indizieren möchten. Dann, wenn Sie Daten hinzufügen NCache, wird überprüft, ob Sie diese Objekte hinzufügen. Und wenn ja, dann verwendet es .NET Reflection, um Daten aus den indizierten Attributen zu extrahieren und seinen internen Index zu erstellen. Wenn Sie dann den Cache mit Cache.Search() oder Cache.SearchEntries() abfragen, NCache verwendet diese Indizes, um die gewünschten Objekte schnell zu finden, und gibt sie Ihnen zurück.

Indizieren von Objektattributen vor dem Starten des Cache
Abbildung 1: Indizieren von Objektattributen vor dem Starten des Cache

Bitte beachten Sie, dass jedes Mal, wenn Sie Indizes für Objektattribute angeben, die Verarbeitungszeit für Vorgänge zum Hinzufügen, Einfügen und Entfernen etwas verlängert wird. Der Get-Vorgang ist jedoch nicht betroffen.

Abfragen verschiedener Caching-Topologien

Obwohl das Suchverhalten aus Sicht der Clientanwendung unabhängig davon, welche Caching-Topologien Sie verwenden, dasselbe ist, variieren die Interna der Suche von Topologie zu Topologie. Wenn Sie beispielsweise eine Suche in einem replizierten Cache durchführen, wird Ihre Suche vollständig auf dem Cache-Server durchgeführt, von dem aus Sie diese Suche initiiert haben. Denn dort steht der gesamte Cache zur Verfügung. So wird eine Abfrage in einem replizierten Cache ausgeführt.

Abfrage läuft lokal auf einem Server
Abbildung 2: Abfrage läuft lokal auf einem Server

Wenn Sie jedoch über eine partitionierte oder partitionierte Replikat-Caching-Topologie verfügen, befinden sich nicht alle Daten auf einem einzelnen Cache-Knoten im Cluster. In dieser Situation sendet der Cache-Server, auf dem die Abfrage initiiert wird, die Abfrage an alle anderen Server im Cluster und führt sie auch lokal aus. Die Abfrage läuft dann in allen Servern parallel und ihre Ergebnisse werden von allen Knoten an diesen Ursprungsserverknoten zurückgesendet. Dieser Serverknoten kombiniert dann alle Ergebnisse (führt eine "Vereinigung" durch) und gibt sie an den Client zurück. Unten ist ein Diagramm, das all dies zeigt.

Die Abfrage wird auf allen Serverknoten parallel ausgeführt
Abbildung 3: Abfrage läuft parallel auf allen Serverknoten

Ihre .NET-Assemblys

In NCache, erfolgt die Indizierung auf den Serverknoten. Jedoch, NCache verwendet .NET Reflection auf dem Client-Ende, um die Werte von Objektattributen zu extrahieren und sie an den Server zu senden. Daher sind Ihre .NET-Assemblys, die die Objektdefinition enthalten, nur auf der Clientseite erforderlich, auf der sich Ihre Anwendung befindet. Unabhängig davon, ob Sie im InProc- oder im OutProc-Modus ausgeführt werden, müssen sich Ihre Assemblys in einem Verzeichnis befinden, in dem Ihre Clientanwendung darauf zugreifen kann.

Zusätzlich NCache unterstützt auch die Objektabfragesprache für Java-Clients.

Syntax der Abfragesprache

NCache unterstützt eine SQL-ähnliche Sprache namens Object Query Language (OQL). Diese Sprache hat die folgende Syntax in 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;

Sie können mehrere Ausdrücke mit AND und OR kombinieren und verschachtelte Klammern verwenden. Die vollständige Syntaxgrammatik der Abfragesprache ist unten angegeben.

<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> 

Zusammenfassung

Wie du gesehen hast, NCache macht es sehr einfach, den verteilten Cache abzufragen. Dies ist eine leistungsstarke Funktion, mit der Sie Ihren Cache sinnvoller nutzen und Dinge darin leichter finden können. Hör zu.


Autor: Iqbal Khan arbeitet für Alachisoft , ein führendes Softwareunternehmen, das Lösungen für verteiltes .NET- und Java-Caching, O/R-Mapping und SharePoint-Speicheroptimierung anbietet. Sie erreichen ihn unter iqbal@alachisoft.com €XNUMX.

© Copyright Alachisoft 2002 - Alle Rechte vorbehalten NCache ist eine eingetragene Marke der Diyatech Corp.