Skalierung von .NET Core-Anwendungen für extreme Leistung

 

Einführung

.NET Core und ASP.NET Core erfreuen sich aufgrund ihres einfachen Designs, ihrer geringen Größe, ihrer Open-Source-Natur und ihrer Kompatibilität mit Windows und Linux zunehmender Beliebtheit. Daher migrieren viele bestehende Anwendungen vom .NET Framework zu .NET Core. Nahezu alle neuen Anwendungen werden mit .NET Core entwickelt.

Viele dieser .NET Core-Anwendungen sind stark frequentiert und verarbeiten Millionen von Nutzern und Transaktionen. Daher haben diese Anwendungen einen enormen Einfluss auf Ihr Unternehmen und sind deshalb von großer Bedeutung.

 

Wer braucht Skalierbarkeit?

Die .NET Core-Anwendungen, die Skalierbarkeit benötigen, sind in der Regel Serveranwendungen, die eine große Anzahl von Transaktionen sehr schnell und mit extrem kurzen Antwortzeiten verarbeiten müssen. Viele dieser Anwendungen haben direkten Kundenkontakt und bearbeiten daher Kundenanfragen. Werden Kundenanfragen nicht schnell genug bearbeitet, entstehen dem Unternehmen hohe Kosten durch Umsatzeinbußen und den Verlust zufriedener Kunden.

Folgende .NET Core-Anwendungen erfordern Skalierbarkeit:

  1. Web-Apps (ASP.NET Core): Hierbei handelt es sich in der Regel um kundenorientierte Anwendungen, bei großen Unternehmen kann es sich jedoch auch um interne Anwendungen handeln.
  2. Webdienste (ASP.NET Core): Dabei kann es sich entweder um die direkte Bereitstellung von Web-APIs für Kunden handeln oder um Teil einer anderen Anwendung mit hohem Transaktionsaufwand, die Anwendungsebenenlogik in diesen Webdiensten enthält.
  3. Echtzeit-Webanwendungen (ASP.NET Core SignalR): Hierbei handelt es sich um Echtzeitanwendungen, die ihren Benutzern mithilfe des SignalR-Frameworks von ASP.NET Core häufige Aktualisierungen bereitstellen müssen. Da sie in der Regel kundenorientiert sind, müssen sie zudem schnell funktionieren.
  4. Microservices (.NET Core): Dabei handelt es sich um eine neue Anwendungsarchitektur für serverseitige Anwendungen. Und genau wie Webservices sind diese Microservices normalerweise Teil einer kundenorientierten Webanwendung oder einer kundenorientierten Webservices-Anwendung. Daher stellen sie auch bei hoher Transaktionslast hohe Leistungsanforderungen.
  5. Andere Serveranwendungen (.NET Core): Es gibt eine Vielzahl anderer Serveranwendungen, die eine große Menge an Transaktionen sehr schnell verarbeiten müssen. Dies können Stapelverarbeitungsanwendungen sein, die verschiedene Arten von Backend-Workflows verarbeiten, oder Stream-Verarbeitungsanwendungen, die große Datenmengen für die Verarbeitung nahezu in Echtzeit erfassen. Die Liste geht weiter.
 

Das Problem: Skalierbarkeitsengpässe

Interessanterweise verfügen alle oben genannten Anwendungen über sehr skalierbare Architekturen auf Anwendungsebene. Jeder von ihnen ermöglicht Ihnen eine lineare Skalierung, wenn Ihre Transaktionslast wächst, indem Sie weitere Server, VMs oder Containerinstanzen zusammen mit einem Load Balancer hinzufügen.

Trotz einer sehr skalierbaren Architektur auf Anwendungsebene stoßen .NET Core-Serveranwendungen heute auf erhebliche Skalierungsprobleme. Diese Probleme treten in verschiedenen Bereichen auf, wie zum Beispiel:

  1. Anwendungsdatenbanken (relationale Datenbanken): Das ist der größte Engpass überhaupt. Ich erkläre es weiter unten genauer.
  2. ASP.NET Core Session Storage: Wenn Sitzungen in SQL Server gespeichert werden, wird Ihre ASP.NET Core-Anwendung mit erheblichen Engpässen konfrontiert sein.
  3. ASP.NET Core – Wiederholte Seitenverarbeitung: Wenn dieselben Seiten wiederholt ausgeführt werden und ihre Ausgabe oder Antwort gleich bleibt, handelt es sich um eine Verschwendung von Ressourcen und einen Leistungsengpass.
  4. ASP.NET Core SignalR Backplane Provider: Wenn eine Live-Webanwendung, die SignalR verwendet, skaliert werden muss, kann der Backplane-Anbieter leicht zu einem Engpass werden.
  5. Pub/Sub-Nachrichten (nicht im Speicher): Wenn Ihre .NET Core-Anwendung Pub/Sub-Messaging verwendet, dann ist die Wahrscheinlichkeit hoch, dass es sich nicht um In-Memory-Messaging handelt und es sich daher um einen Flaschenhals handelt.
Leistungsengpässe in ASP.NET Core
Abbildung 1: ASP.NET Core-Anwendung stößt an Skalierungsgrenzen
 

Engpass bei relationalen Datenbanken

Der größte Engpass für alle stark frequentierten .NET Core-Anwendungen ist ihre Anwendungsdatenbank. Die meisten Anwendungen nutzen heute noch relationale Datenbanken wie SQL Server oder Oracle. Diese Datenbanken werden schnell zu Skalierungsengpässen, wenn die Transaktionslast dieser Anwendungen steigt. Dies gilt unabhängig davon, ob Sie SQL Server auf einer virtuellen Maschine oder Azure SQL-Datenbank verwenden.

Dies liegt daran, dass eine relationale Datenbank nicht wie eine NoSQL-Datenbank logisch partitioniert werden kann, sondern an einem einzigen physischen Ort verbleibt; selbst eine Partitionierung auf Spaltenebene entspricht nicht dem typischen NoSQL-Partitionierungsstil. Daher lässt sich die Transaktionskapazität der Datenbankebene nicht durch Hinzufügen weiterer Datenbankserver wie bei einer NoSQL-Datenbank erweitern.

Während Ihre Anwendungsschicht beispielsweise problemlos 10, 20, 30 oder mehr Anwendungsserver umfassen kann, wenn Ihre Transaktionslast zunimmt, kann Ihre Datenbankschicht überhaupt nicht in der gleichen Weise wachsen.

Aus all diesen Gründen wird Ihre relationale Datenbank zu einem Leistungsengpass für alle darin gespeicherten Daten (Anwendungsdaten oder andere Daten).

 

Die In-Memory-Optimierungen des Datenbankservers reichen nicht aus

SQL Server hat In-Memory-Optimierungen eingeführt, um die Anzahl der Transaktionen pro Sekunde zu erhöhen. Oracle hat auch eine eigene Version von In-Memory-Tabellen bereitgestellt.

Während In-Memory-Optimierungen zu Leistungsverbesserungen führen, lösen sie nicht das Kernproblem der linearen Skalierbarkeit. In-Memory-Tabellen werden im Allgemeinen für schreibgeschützte Daten verwendet. Um eine schreibgeschützte Transaktionskapazität zu skalieren, müssen Sie auf High-End-Computern weitere Instanzen von SQL Server hinzufügen.

Auch für In-Memory-Tabellen gelten Einschränkungen hinsichtlich der Datengröße. Sie können keine großen Tabellen im Speicher ablegen, da die gesamte Tabelle im Speicher abgelegt werden muss. Und ihre Replikation auf andere SQL Server-Instanzen kann nur auf andere In-Memory-Tabellen und nicht auf eine richtige Datenbank erfolgen.

Zusammenfassend lässt sich sagen, dass diese In-Memory-Optimierungen in SQL Server- und Oracle-Datenbanken die Skalierungsanforderungen Ihrer .NET Core-Anwendung nicht vollständig erfüllen können.

 

NoSQL-Datenbanken sind nicht die Antwort

Einer der Gründe für die Popularität von NoSQL-Datenbanken liegt in der effizienten Datenpartitionierung mittels Hash-basierter und anderer Algorithmen. Dadurch werden viele Skalierungsprobleme hinsichtlich der Transaktionskapazität gelöst, mit denen relationale Datenbanken wie SQL Server und Oracle konfrontiert sind.

Es gibt jedoch Gründe, warum NoSQL-Datenbanken nicht die ideale Lösung für diese Datenbankengpässe darstellen.

  1. Kein In-Memory-Store: NoSQL-Datenbanken speichern ihre Daten wie relationale Datenbanken auf der Festplatte. Das bedeutet, dass die geringe Leistung der Festplatte unabhängig von den getroffenen Maßnahmen letztendlich zum Leistungsengpass wird.
  2. Kann die meiste Zeit nicht verwendet werden: NoSQL-Datenbanken erfordern, dass Sie relationale Datenbanken wie SQL Server und Oracle aufgeben und durch eine NoSQL-Datenbank ersetzen. Dies ist in den meisten Fällen aus technischen und nicht-technischen Gründen nicht möglich. Ihr Unternehmen ist im Wesentlichen von Ihrer relationalen Datenbank abhängig und kann diese nicht ohne Weiteres aufgeben. Daher können Sie die Vorteile einer NoSQL-Datenbank nicht voll ausschöpfen.
 

Die Lösung: Verteilter In-Memory-Cache (NCache)

Die Lösung für alle oben genannten Probleme ist die Verwendung eines In-Memory Distributed Cache wie NCache in Ihrer .NET Core-Anwendungsbereitstellung. NCache ist ein Open-Source-Cache für .NET und .NET Core, der extrem schnell und linear skalierbar ist. Man kann ihn sich als verteilten In-Memory-Datenspeicher vorstellen. Die In-Memory-Architektur sorgt für extreme Geschwindigkeit, die verteilte Architektur für lineare Skalierbarkeit.

NCache ist linear skalierbar, da es einen TCP-Cluster kostengünstiger Cache-Server aufbaut (gleiche Konfiguration wie Ihre Web-App-Server, aber mit mehr Speicher) und die Speicher- und CPU-Ressourcen aller dieser Server in einer logischen Kapazität zusammenfasst. NCache Anschließend können Sie diesem Cluster zur Laufzeit Cache-Server hinzufügen, wenn Ihre Transaktionslast zunimmt. Und da NCache Da alles im Arbeitsspeicher stattfindet, ist es superschnell und bietet Ihnen Antwortzeiten im Submillisekundenbereich, die Sie von relationalen Datenbanken oder sogar NoSQL-Datenbanken nicht erwarten können.

Zusätzlich zur Bereitstellung linearer Skalierbarkeit bietet ein verteilter Cache z NCache repliziert Daten intelligent, sodass Ihre Leistung nicht beeinträchtigt wird und gleichzeitig Datenzuverlässigkeit gewährleistet wird, falls ein Cache-Server ausfällt.

NCache Bereitgestellt im Unternehmen für .NET Core
Abbildung 2: NCache Bereitgestellt im Unternehmen für .NET Core

NCache Ermöglicht die Skalierung Ihrer .NET Core-Anwendungen durch Folgendes:

  • Zwischenspeichern von Anwendungsdaten
  • ASP.NET Core Session Storage
  • ASP.NET Core Antwortcache-Middleware
  • ASP.NET Core SignalR Backplane
  • Pub/Sub-Messaging und CQ-Ereignisse (In-Memory)
  • Kontinuierliche Abfrageereignisse (In-Memory)
 

Zwischenspeichern von Anwendungsdaten

Der größte Engpass bei .NET Core-Anwendungen ist die „Anwendungsdatenbank“. Das Schöne daran ist, dass NCache Im Gegensatz zu NoSQL-Datenbanken NCache fordert Sie nicht auf, die Nutzung Ihrer vorhandenen relationalen Datenbank einzustellen. Sie können weiterhin SQL Server, Azure SQL-Datenbank, Oracle usw. als Datenbank verwenden und dennoch eine lineare Skalierbarkeit erreichen NCache zusätzlich zu Ihrer relationalen Datenbank. Das ist weil NCache beseitigt alle Engpässe bei der Skalierbarkeit relationaler Datenbanken, da im Gegensatz zu Ihrer Datenbank NCache ist tatsächlich linear skalierbar.

Mit Application Data Caching können Sie Ihre Datenbankengpässe beseitigen. NCache ermöglicht es Ihnen, Anwendungsdaten zwischenzuspeichern und teure Datenbankfahrten zu reduzieren. Sie können davon ausgehen, dass 80–90 % des Datenbankdatenverkehrs dorthin umgeleitet werden NCache. Dies verringert den Druck auf Ihre Datenbank und ermöglicht eine schnellere Leistung sowie die Bewältigung größerer Transaktionslasten ohne Verlangsamung.

Anwendungsdaten-Caching bedeutet, dass Sie alle Anwendungsdaten zwischenspeichern, die Sie aus Ihrer relationalen Datenbank erhalten. Dies geschieht normalerweise in Form von Domänenobjekten (auch Entitäten genannt). Hier ist ein Beispiel für die Verwendung eines verteilten Caches NCache für das Zwischenspeichern von Anwendungsdaten.

Customer Load(string custId)
{
  ICache cache = CacheManager.GetCache("myCache");
  string key = "Customer:CustomerID:" + custId;
  Customer cust = cache.Get<Customer>(key);
  
  if (cust == null)
  {
    // Item not in cache so load from db
    LoadCustomerFromDb(cust);
    // Add item to cache for future reference
    cache.Add(key, cust);
    }
    return cust;
}

Abbildung 3: Verwendung des verteilten In-Memory-Cache für das App-Daten-Caching

 

ASP.NET Core Session Storage

Ein weiterer möglicher Engpass entsteht, wenn Sie Ihre ASP.NET Core-Sitzungen in SQL Server oder einem separaten MemoryCache speichern. Beide Optionen weisen erhebliche Einschränkungen hinsichtlich Leistung und Skalierbarkeit auf. Die Speicherung in SQL Server ist für ASP.NET Core-Sitzungen ungeeignet und wird, ähnlich wie bei Anwendungsdaten, schnell zum Flaschenhals.

NCache ist ein hervorragender Ort zum Speichern Ihrer ASP.NET Core Sessions, da es viel schneller und skalierbarer ist als andere Speicheroptionen. NCache Es ist schneller, da es im Arbeitsspeicher arbeitet und eine Key-Value-Schnittstelle bereitstellt, wobei der Wert ein „Objekt“ ist, was eine ASP.NET Core-Session ist. Außerdem ist es skalierbar, da es sich um einen verteilten Cache handelt.

Und, NCache Zudem werden ASP.NET Core-Sitzungen durch die ausgefeilten Caching-Topologien intelligent repliziert, sodass selbst bei Ausfall eines Cache-Servers keine Sitzungsdaten verloren gehen. Diese Replikation ist notwendig, weil NCache Stellt einen In-Memory-Speicher bereit und der Speicher verletzt den Speicher.

NCache beschleunigt außerdem die Serialisierung der ASP.NET Core Session, die erforderlich ist, bevor sie außerhalb des Prozesses gespeichert werden kann. NCache Dies geschieht durch die Verwendung der Funktion „Dynamische kompakte Serialisierung“, die zehnmal schneller ist als die reguläre Serialisierung von .NET und .NET Core. Diese Funktion kann ohne Codeänderungen genutzt werden.

Sie können verwenden NCache als Ihren ASP.NET Core Session-Speicher auf zwei Arten.

  1. IDistributedCache für ASP.NET Core-Sitzung: NCache hat die IDistributedCache-Schnittstelle implementiert, die Ihnen ein automatisches Plug-in ermöglicht NCache als Ihr ASP.NET Core Session-Speicheranbieter. Diese Option bietet jedoch weniger Funktionen als die andere.
  2. NCache Anbieter für ASP.NET Core-Sitzungen: NCache Es wurde außerdem ein eigener, funktionsreicherer ASP.NET Core Session-Speicheranbieter implementiert, den Sie verwenden können. Dieser bietet zusätzliche Funktionen wie Sperrmechanismen, Timeouts usw.

Nachfolgend finden Sie ein Beispiel, wie Sie Ihre ASP.NET Core-Anwendung für die Verwendung konfigurieren können. NCache Sitzungsanbieter:

public class Startup
{
  public void ConfigureServices(IServiceCollection services)
  {
    // Specify NCache as the session provider
    services.AddNCacheSession(Configuration.GetSection("NCacheSettings"));
    ...
  }
    
  public void Configure(IApplicationBuilder app, ...)
  {
    // select NCache session provider for ASP.NET Core
    app.UseNCacheSession();
    ...
  }
}

Abbildung 4: Plug-in NCache als ASP.NET Core-Sitzungen

 

ASP.NET Core Antwortcache-Middleware

ASP.NET Core-Anwendungen, die ansonsten dynamische Inhalte aufweisen, stoßen auf Situationen, in denen sich der Inhalt oder die Antwort einiger Seiten über mehrere Anfragen hinweg nicht ändert. Diese Seiten müssen jedoch bei jeder Anfrage neu ausgeführt werden. Dies belastet die Ressourcen des Webservers und alle Ebenen der Anwendung unnötig. Infolgedessen entstehen Leistungsengpässe, und die Skalierbarkeit der Anwendung wird eingeschränkt.

public class Startup
{
  public void ConfigureServices(IServiceCollection services)
  {
    // Turn on ASP.NET Core Response Cache with IDistributedCache
    services.AddResponseCaching();
    
    // Select NCache as IDistributedCache provider
    services.AddNCacheDistributedCache(Configuration.GetSection("NCacheSettings"));
    ...
  }
}

Abbildung 5: Plug-in NCache als ASP.NET Core Response Cache Middleware

Um den Mehraufwand bei wiederholter Seitenausführung zu reduzieren, wenn sich die Seitenantwort nicht ändert, bietet ASP.NET Core einen Mechanismus zum Zwischenspeichern von Seitenantworten namens ASP.NET Response Cache Middleware. NCache hat die IDistributedCache-Schnittstelle in ASP.NET Core implementiert, wodurch Sie nahtlos einbinden können NCache als Ihre ASP.NET Core Response Cache Middleware.

So können Sie verwenden NCache Um die Antworten von ASP.NET Core-Seiten für einen bestimmten Zeitraum zwischenzuspeichern, sodass beim nächsten Aufruf derselben Seite mit denselben Parametern diese zwischengespeicherte Antwort zurückgegeben werden kann, anstatt die gesamte Seite erneut auszuführen, finden Sie unten ein Codebeispiel zur Konfiguration. NCache als Ihre ASP.NET Core Response Cache Middleware.

 

ASP.NET Core SignalR Backplane

Wenn Ihre ASP.NET Core-Anwendung eine Echtzeit-Webanwendung ist, verwendet sie höchstwahrscheinlich ASP.NET Core SignalR, um dieses Echtzeitverhalten zu realisieren. Echtzeit-Webanwendungen senden häufige Aktualisierungen vom Server an den Client. Beispiele für solche Anwendungen sind Spiele, Auktionsplattformen, Abstimmungssysteme, soziale Netzwerke usw.

Läuft Ihre ASP.NET Core-Anwendung in einer Load-Balancing-Umgebung mit mehreren Servern, benötigt sie einen ASP.NET Core SignalR Backplane-Provider, um Ereignisse zwischen den Webservern zu verteilen. Dieser Backplane muss skalierbar sein. Andernfalls stößt Ihre ASP.NET Core SignalR-Anwendung an ihre Leistungsgrenzen.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Specify NCache as the ASP.NET Core SignalR Backplane
        services.AddSignalR().AddNCache(ncacheOptions =>
        { ncacheOptions.CacheName = "myPartitionedCache"; });
        ...
    }
    
    public void Configure(IApplicationBuilder app, ...)
    {
        // Use SignalR in ASP.NET Core
        app.UseSignalR(config => { config.MapHub<MessageHub>("/messages"); });
        ...
    }
}

Abbildung 6: Plug-in NCache als ASP.NET Core SignalR Backplane Provider

NCache hat einen ASP.NET Core SignalR Backplane-Provider implementiert. NCacheDer ASP.NET Core SignalR Backplane-Provider nutzt die Pub/Sub-Messaging-Funktionen von NCache Diese sind extrem schnell, da sie vollständig im Arbeitsspeicher verarbeitet werden. Dadurch kann Ihre ASP.NET Core SignalR-Anwendung die SignalR-Ereignisweiterleitung zwischen allen Webservern und somit auch zu den Clients beschleunigen.

Und dadurch ist Ihre Echtzeit-Webanwendung reaktionsfähiger bei der Bereitstellung dieser häufigen Updates für die Clients. Und Sie können die Anzahl der Clients kontinuierlich erhöhen und auch weitere Webserver hinzufügen, ohne Leistungsengpässe befürchten zu müssen.

 

Pub/Sub-Messaging (In-Memory)

Wenn Ihre .NET Core-Anwendung Pub/Sub-Messaging oder Ereignisse benötigt, verwendet sie höchstwahrscheinlich eine Pub/Sub-Messaging-Plattform, die nicht vollständig im Arbeitsspeicher arbeitet, sondern alle Nachrichten auf der Festplatte speichert. Dies kann leicht zu einem Leistungsengpass führen, insbesondere bei Anwendungen mit hohem Transaktionsvolumen.

NCache Bietet außerdem ein Pub/Sub-Messaging, das superschnell ist, da es vollständig im Speicher läuft. Und es repliziert alle Nachrichten an andere NCache Server, um sicherzustellen, dass es beim Ausfall eines Servers nicht zu Datenverlusten kommt.

Wenn Ihre .NET Core-Anwendung also Folgendes verwendet NCache Als Pub/Sub-Messaging-Plattform wird es eine superschnelle Leistung und lineare Skalierbarkeit erleben NCache selbst ist linear skalierbar.

Nachfolgend finden Sie ein Beispiel dafür, wie Sie Pub/Sub Messaging verwenden können, das von bereitgestellt wird NCache in Ihrer .NET Core-Anwendung.

private void PublishMessage (string topicName)
{
    ITopic topic = _cache.MessagingService.GetTopic(topicName);
    Order order = Order.GenerateOrder<Order>();
    // Publish message containing "order" with expiry
    Message message = new Message(order, new TimeSpan(0, 0, 15));
    topic.Publish(message, DeliveryOption.All, true);
}

private ITopicSubscription SubscribeMessage (string topicName)
{
    ITopic topic = _cache.MessagingService.GetTopic(topicName);
    // Subscribes to the topic. Message delivered to MessageReceivedCallback
    return topic.CreateSubscription(MessageReceivedCallback);
}
static void MessageReceivedCallback(object sender, MessageEventArgs args) { ... }

Abbildung 7: Verwendung von Pub/Sub-Messaging in .NET Core-Anwendungen

 

Zwischenspeichern von Anwendungsdaten

Der größte Skalierungsengpass, den Ihre .NET Core-Anwendung beseitigen muss, liegt in der Anwendungsdatenbank. Hier können Ihre Anwendungen durch Daten-Caching eine hohe Leistung und lineare Skalierbarkeit erreichen. Der Grund dafür ist einfach: Die meisten .NET Core-Anwendungen greifen ständig auf große Datenmengen in der Datenbank zu.

 

Halten Sie den Cache frisch

Wenn es um das Zwischenspeichern von Anwendungsdaten geht, besteht die größte Angst der Menschen darin, dass der Cache veraltet ist, d. h. er enthält eine ältere Version der Daten, die bereits von einem anderen Benutzer oder einer anderen Anwendung in der Datenbank geändert wurde.

  1. Referenz vs. Transaktionsdaten

    Diese Angst, dass ein Cache veraltet, ist so groß, dass die meisten Menschen nur schreibgeschützte oder statische Daten (Referenzdaten) zwischenspeichern. Diese schreibgeschützten Daten machen jedoch nur 20 % der gesamten Daten in Form von Nachschlagetabellen und anderen Referenzdaten aus. Der Großteil der Daten in der Datenbank sind Transaktionsdaten, einschließlich Kunden, Konten, Aktivitäten usw. Und wenn Sie diese Transaktionsdaten nicht zwischenspeichern, profitieren Sie nicht vollständig vom Caching.

    Der wahre Vorteil des Caching liegt also darin, dass Sie alle Arten von Daten zwischenspeichern können, ohne befürchten zu müssen, dass das Caching veraltet ist. NCache bietet eine Vielzahl von Funktionen, um dieses Problem zu lösen.

  2. Cache mit Datenbank synchronisieren

    Der effektivste Weg, Ihren Cache auf dem neuesten Stand zu halten, besteht darin, ihn immer mit Ihrer Datenbank zu synchronisieren. NCache können Sie dies wie folgt für eine Vielzahl von Datenbanken tun:

    1. Cache mit SQL Server synchronisieren: Verwenden von SqlDependency- und DB-Ereignisbenachrichtigungen
    2. Cache mit Oracle synchronisieren: Verwendung von OracleDependency- und DB-Ereignisbenachrichtigungen
    3. Cache mit Cosmos DB synchronisieren: Verwenden der Cosmos DB-Änderungsfeedverarbeitung
    4. Cache mit beliebigen Datenbanken synchronisieren (abfragebasiert): mit automatisierten NCache Bereitstellung einer abfragebasierten Datenbanksynchronisierung.

Wenn Sie Ihren Cache mit SQL Server synchronisieren, fragen Sie NCache um sich als Client von SQL Server zu registrieren und dann einen SqlDependency-Aufruf zusammen mit einem auf SQL-Abfragen basierenden Datensatz auszugeben. Wenn der SQL Server dann Änderungen in diesem Datensatz erkennt, benachrichtigt er ihn NCache darüber

private static void CreateSqlDependency (Product product)
{
    string connectionString = "Data Source=localhost;Database=northwind;...";
    // SQL stmt on which the SQL Dependency is created in SQL Server
    string sqlStmt = "SELECT ProductID, ProductName, QuantityPerUnit, UnitPrice " +
    "FROM dbo.PRODUCTS WHERE ProductID = " + product.Id;
    CacheDependency sqlDependency = new SqlCacheDependency(connectionString, sqlStmt);
    CacheItem cacheItem = new CacheItem(product) { Dependency = sqlDependency };
    string key = "Product:ProductId:" + product.Id; ;
    cache.Add(key, cacheItem);
}

Abbildung 8: Verwenden von SqlDependency zum Synchronisieren des Caches mit SQL Server

Dann, NCache Entfernt dieses Element aus dem Cache, sodass die Anwendung das nächste Mal, wenn sie es benötigt, die neueste Kopie aus der Datenbank abrufen muss. Wenn Sie den Read-through-Handler verwenden (siehe unten), dann NCache kann die neueste Kopie auch automatisch für Sie aus der Datenbank laden. Unten finden Sie ein Beispiel dafür, wie Sie SqlDependency verwenden können, um Ihren Cache mit SQL Server zu synchronisieren.

 

Lese- und Schreib-Cache

Read-through-Cache ist ein Cache, der Daten aus Ihrer Datenbank lesen kann, indem er einen Readthrough-Handler aufruft, den Sie entwickelt und dem Cache bereitgestellt haben. Ebenso ist ein Write-through-Cache in der Lage, Datenänderungen in Ihre Datenbank zu schreiben, indem er einen Write-through-Handler aufruft, den Sie entwickelt und dem Cache bereitgestellt haben. Der Write-Behind-Cache ist dasselbe wie der Write-Through-Cache, mit der Ausnahme, dass die Datenbankaktualisierungen asynchron erfolgen.

Read-through, Write-through und Write-behind bieten viele Vorteile für Ihre .NET Core-Anwendungen, darunter:

  1. App-Code vereinfachen: Verschieben Sie Persistenzcode aus Ihrer Anwendung in die Caching-Ebene.
  2. Elemente automatisch aus der Datenbank neu laden: Verwenden Sie „Durchlesen bei Ablauf“ oder „DB-Synchronisierungszeit“.
  3. Schnelleres Schreiben: Verwenden Sie asynchrone Datenbankschreibvorgänge mit Write-Behind.

Nachfolgend finden Sie ein Beispiel dafür, wie Sie Read-through mit verwenden können NCache.

// Read through handler for SQL Server
public class SqlReadThruProvider : Runtime.DatasourceProviders.IReadThruProvider
{
    public void Init(IDictionary parameters, string cacheId) {}
    public void Dispose() {}
    // Get object from the database/data-source based on the key
    public ProviderCacheItem LoadFromSource(string key) {}
    // Bulk-Get objects from the database/data-source based on the keys
    public IDictionary<string, ProviderCacheItem> LoadFromSource(ICollection<string> keys)
    {}
}

Abbildung 9: Verwendung des Read-through-Handlers mit NCache

 

Durchsuchen Sie den Cache

Sobald Sie mit dem Zwischenspeichern aller Daten vertraut sind, können Sie damit beginnen, viele Daten in einem verteilten Cache abzulegen. Hier können Sie mit einem weiteren besonderen Problem konfrontiert werden: Wie Sie Ihre Daten schnell und einfach finden können. Da es sich bei den meisten verteilten Caches um Schlüsselwertspeicher handelt, wird es sehr schwierig, den Überblick über alle Ihre Daten allein über Schlüssel zu behalten.

Das ist wo NCache bietet Ihnen verschiedene Möglichkeiten, schnell Daten aus Ihrem Cache zu finden. Beispiele beinhalten:

  1. Gruppendaten im Cache (Gruppe/Untergruppe, Tags, benannte Tags): NCache bietet Ihnen mehrere Möglichkeiten, Ihre Daten logisch zu gruppieren und später die gesamte Gruppe in einem Aufruf abzurufen. Das vereinfacht Ihr Datenmanagement erheblich.
  2. Daten mit Abfragen durchsuchen (SQL/LINQ): Zusätzlich zum Suchen von Daten basierend auf Gruppen-API-Aufrufen, NCache bietet Ihnen außerdem die Möglichkeit, den Cache nach Daten zu durchsuchen, die auf Objektattributen, Gruppen, Tags und benannten Tags basieren.
  3. Parallele Suchen: Seit NCache ist von Natur aus verteilt. Wenn Ihre Anwendung eine Suchabfrage oder einen Such-API-Aufruf ausgibt, wird diese Abfrage parallel auf allen Cache-Servern ausgeführt. Anschließend werden die Ergebnisse aller Server an den Client-Computer (d. h. den Anwendungsserver) zurückgegeben, wo sie zusammengeführt werden, bevor die endgültigen Ergebnisse an Ihre Anwendung zurückgegeben werden. Dies beschleunigt Ihre Cache-Suchen erheblich.

Nachfolgend finden Sie ein Beispiel dafür, wie Sie LINQ-basierte Abfragen verwenden können NCache.

// Search the cache based on object attributes by using LINQ
IQueryable>Product< products = new NCacheQuery<Product>(_cache);
var result = from product in products
where product.Id > 10
select product;
if (result != null)
{
    foreach (Product p in result1)
    {
        // Process each “product” fetched from the database
        Console.WriteLine("ProductID : " + p.Id);
    }
}

Abbildung 10: Verwenden von LINQ-Abfragen mit NCache

 

NCache Architektur für extreme Skalierbarkeit

Stark frequentierte .NET Core-Anwendungen dürfen nicht ausfallen, insbesondere nicht zu Spitzenzeiten. Für diese Anwendungsarten gibt es drei wichtige Architekturziele, die ein guter verteilter In-Memory-Cache erfüllen sollte. NCache erfüllt.

  1. Client-Cache (InProc-Geschwindigkeit)
  2. Lineare Skalierbarkeit mit schneller Replikation
  3. Hohe Verfügbarkeit durch dynamisches Clustering

Lassen Sie mich die einzelnen Punkte unten erklären.

 

Client-Cache (InProc-Geschwindigkeit)

NCache stellt einen Client-Cache bereit, bei dem es sich um einen lokalen Cache ganz in der Nähe Ihrer Anwendung handelt. Es kann sich entweder um InProc (d. h. es befindet sich in Ihrem Anwendungsprozess) oder um lokales OutProc handeln. In jedem Fall bietet es einen sehr schnellen Zugriff auf eine Teilmenge der zwischengespeicherten Daten, die Ihre Anwendung auf diesem App-Server zu diesem Zeitpunkt benötigt. Gleichzeitig bleibt der Client-Cache mit der Caching-Ebene synchronisiert, sodass alle Daten, die von anderen Benutzern oder Anwendungen in der Caching-Ebene geändert werden, sofort an den Client-Cache weitergegeben werden. Der Client ermöglicht Ihnen InProc-Geschwindigkeit und ist gleichzeitig Teil einer sehr skalierbaren Caching-Ebene.

Client-Cache-Architektur in NCache für InProc-Geschwindigkeit
Abbildung 11: Client-Cache-Architektur in NCache für InProc-Geschwindigkeit
 

Lineare Skalierbarkeit mit schneller Replikation

Eines der wichtigsten architektonischen Ziele von NCache besteht darin, durch seine Caching-Topologien eine lineare Skalierbarkeit mit Datenzuverlässigkeit zu erreichen. Hier sind einige NCache Caching-Topologien die dazu beitragen, diese beiden Ziele zu erreichen.

  1. Partitionierter Cache: NCache Partitioniert den Cache basierend auf der Anzahl der Cache-Server und weist jedem Cache-Server eine Partition zu. Außerdem wird die Anzahl der Partitionen angepasst, wenn Sie zur Laufzeit Cache-Server hinzufügen oder entfernen. Die Partitionierung ist die wichtigste Möglichkeit, lineare Skalierbarkeit sicherzustellen, denn wenn Sie weitere Server hinzufügen, erhöht diese Caching-Topologie die Gesamtspeichergröße und auch die CPU-Verarbeitungsleistung.
  2. Partitionierter Replikat-Cache: Zusätzlich zur Partitionierung NCache stellt außerdem Replikate für jede Partition bereit. Diese Replikate befinden sich auf anderen Cache-Servern als die Partition selbst, um sicherzustellen, dass die Replik sofort verfügbar ist, wenn ein Cache-Server zusammen mit seiner Partition ausfällt. Auf diese Weise wird Datenzuverlässigkeit gewährleistet. Indem jede Partition nur einmal auf einem anderen Cache-Server repliziert wird, NCache erreicht Datenzuverlässigkeit, ohne die lineare Skalierbarkeit zu beeinträchtigen.
Partition-Replica-Caching-Topologie von NCache
Abbildung 12: Partition-Replica-Caching-Topologie von NCache
 

Hohe Verfügbarkeit für 100 % Betriebszeit

Eines der wichtigsten architektonischen Ziele von NCache besteht darin, eine hohe Verfügbarkeit und Cache-Elastizität zu erreichen. Dies geschieht durch die folgenden architektonischen Fähigkeiten:

  1. Selbstheilender Peer-to-Peer-Cache-Cluster: NCache baut einen Cluster von Cache-Servern über TCP/IP auf. Dieser Cluster hat eine Peer-to-Peer-Architektur Das bedeutet, dass es keine Master/Slave-Knoten und kein Clustering nach Mehrheitsregeln gibt. Stattdessen ist jeder Knoten ein gleichberechtigter Peer. Das ermöglicht NCache um Situationen zu bewältigen, in denen ein Knoten ausfallen könnte und der Cluster sich automatisch anpasst und weiterläuft, ohne dass Ihre Anwendung unterbrochen wird.
  2. Dynamische Konfiguration: Das bedeutet, dass Sie keine Dinge in Konfigurationsdateien fest codieren müssen. NCache gibt Konfigurationsinformationen zur Laufzeit an alle Cache-Clients (d. h. Ihre Anwendungen) weiter.
  3. Unterstützung für Verbindungs-Failover: Fällt ein Cache-Server aus, können der gesamte Cache-Cluster und alle Cache-Clients unterbrechungsfrei weiterarbeiten. Die Cache-Clients arbeiten weiter, indem sie mit anderen Cache-Servern im Cluster interagieren.

Was macht man als nächstes?

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