Eine Anleitung zu Apache Ignite

1. Einführung

Apache Ignite ist eine auf Open-Source-Plattformen basierende, verteilte Plattform. Wir können es als Datenbank, Caching-System oder für die In-Memory-Datenverarbeitung verwenden.

Die Plattform verwendet Speicher als Speicherebene und hat daher eine beeindruckende Leistungsrate. Einfach ausgedrückt: Dies ist eine der schnellsten atomaren Datenverarbeitungsplattformen, die derzeit in der Produktion eingesetzt wird.

** 2. Installation und Setup

**

Schauen Sie sich zunächst die Seite gettingstartseite an, um die Anweisungen zur Einrichtung und Installation zu erhalten.

Die Maven-Abhängigkeiten für die Anwendung, die wir erstellen werden:

<dependency>
    <groupId>org.apache.ignite</groupId>
    <artifactId>ignite-core</artifactId>
    <version>${ignite.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.ignite</groupId>
    <artifactId>ignite-indexing</artifactId>
    <version>${ignite.version}</version>
</dependency>
  • ignite-core ist das nur verbindliche Abhängigkeit für das Projekt ** . Da wir auch mit der SQL interagieren möchten, ist auch ignite-indexing hier.

$\{ignite.version } ist die neueste Version von Apache Ignite.

Als letzten Schritt starten wir den Ignite-Knoten:

Ignite node started OK (id=53c77dea)
Topology snapshot[ver=1, servers=1, clients=0, CPUs=4, offheap=1.2GB, heap=1.0GB]Data Regions Configured:
^-- default[initSize=256.0 MiB, maxSize=1.2 GiB, persistenceEnabled=false]----

Die Konsolenausgabe oben zeigt, dass wir bereit sind.

[[architecture]]

===  3. Speicherarchitektur

**  Die Plattform basiert auf Durable Memory Architecture ** . Dies ermöglicht das Speichern und Verarbeiten der Daten sowohl auf der Festplatte als auch im Arbeitsspeicher. Es erhöht die Leistung, indem die RAM-Ressourcen des Clusters effektiv genutzt werden.

Die Daten im Speicher und auf der Festplatte haben dieselbe binäre Darstellung.

Dies bedeutet keine zusätzliche Konvertierung der Daten, während Sie von einer Ebene zur anderen wechseln.

Die dauerhafte Speicherarchitektur teilt sich in Blöcke fester Größe auf, die als Seiten bezeichnet werden.

Seiten werden außerhalb von Java-Heap gespeichert und in einem RAM organisiert. Es hat eine eindeutige Kennung: __FullPageId__.

Seiten interagieren mit dem Speicher unter Verwendung der Abstraktion __PageMemory__.

Es hilft beim Lesen, Schreiben einer Seite und auch beim Zuweisen einer Seiten-ID. **  Innerhalb des Speichers verknüpft Ignite die Seiten mit __Memory Buffers__ ** .

[[pages]]

===  **  4. Speicherseiten **

Eine Seite kann folgende Zustände haben:

**  Unloaded - Kein Seitenpuffer wurde in den Speicher geladen

**  Löschen - der Seitenpuffer wird geladen und mit den Daten synchronisiert

Platte
**  Durty - Der Seitenpuffer enthält andere Daten als die anderen

auf der Festplatte
**  Dirty in Checkpoint - eine andere Änderung beginnt vor dem

der erste bleibt auf der Festplatte bestehen. Hier startet ein Prüfpunkt und __PageMemory__ speichert für jede Seite zwei Speicherpuffer.

**  Dauerhafter Speicher weist lokal ein Speichersegment mit der Bezeichnung __Data Region __ zu. **  Standardmäßig hat es eine Kapazität von 20% des Clusterspeichers. Die Konfiguration mehrerer Regionen ermöglicht das Speichern der verwendbaren Daten in einem Speicher.

Die maximale Kapazität der Region ist ein Speichersegment. Es handelt sich um einen physischen Speicher oder ein Array mit kontinuierlichen Bytes.

**  Um Speicherfragmentierungen zu vermeiden, enthält eine einzelne Seite mehrere Schlüsselwerteinträge ** . Jeder neue Eintrag wird der optimalsten Seite hinzugefügt. Wenn die Größe des Schlüsselwertpaares die maximale Kapazität der Seite überschreitet, speichert Ignite die Daten auf mehreren Seiten. Die gleiche Logik gilt für die Aktualisierung der Daten.

SQL- und Cache-Indizes werden in Strukturen gespeichert, die als B-Bäume bezeichnet werden. Cache-Schlüssel werden nach ihren Schlüsselwerten sortiert.

===  **  5. Lebenszyklus**

Jeder Ignite-Knoten wird auf einer einzelnen JVM-Instanz ausgeführt. Es ist jedoch möglich zu konfigurieren, dass mehrere Ignite-Knoten in einem einzigen JVM-Prozess ausgeführt werden.

Gehen wir die Lebenszyklusereignistypen durch:

**  __BEFORE__NODE__START__ - vor dem Start des Ignite-Knotens

**  __AFTER__NODE__START__ - wird unmittelbar nach dem Start des Ignite-Knotens ausgelöst

**  __BEFORE__NODE__STOP__ - bevor der Knotenstopp ausgelöst wird

**  __AFTER__NODE__STOP__ - nachdem der Ignite-Knoten angehalten wurde

So starten Sie einen Standard-Ignite-Knoten:

[source,java,gutter:,true]

Ignite ignite = Ignition.start();

Oder aus einer Konfigurationsdatei:

[source,java,gutter:,true]

Ignite ignite = Ignition.start("config/example-cache.xml");

Falls wir mehr Kontrolle über den Initialisierungsprozess benötigen, gibt es mit der __LifecycleBean__-Schnittstelle einen anderen Weg:

[source,java,gutter:,true]

public class CustomLifecycleBean implements LifecycleBean {

@Override
public void onLifecycleEvent(LifecycleEventType lifecycleEventType)
  throws IgniteException {
        if(lifecycleEventType == LifecycleEventType.AFTER__NODE__START) {
           //...
        }
    }
}
Hier können wir die Lebenszyklusereignistypen verwenden, um Aktionen vor oder nach dem Start/Stopp des Knotens auszuführen.

Zu diesem Zweck übergeben wir die Konfigurationsinstanz mit __CustomLifecycleBean__ an die Startmethode:

[source,java,gutter:,true]

IgniteConfiguration configuration = new IgniteConfiguration(); configuration.setLifecycleBeans(new CustomLifecycleBean()); Ignite ignite = Ignition.start(configuration);

[[data__grid]]

===  6. In-Memory-Datengitter

**  Ignite Data Grid ist ein verteilter Schlüsselwertspeicher ** , der dem partitionierten __HashMap__ sehr vertraut ist. Es ist horizontal skaliert. Dies bedeutet, dass mehr Clusterknoten hinzugefügt werden, mehr Daten zwischengespeichert oder im Arbeitsspeicher gespeichert werden.

Es kann eine erhebliche Leistungsverbesserung für die Software von Drittanbietern bieten, wie NoSql, RDMS-Datenbanken als zusätzliche Schicht für das Caching.

[[caching__support]]

====  **  6.1. Caching-Unterstützung **

**  Die Datenzugriffs-API basiert auf der JCache JSR 107-Spezifikation. **

Als Beispiel erstellen wir einen Cache mit einer Vorlagenkonfiguration:

[source,java,gutter:,true]

IgniteCache<Employee, Integer> cache = ignite.getOrCreateCache( "baeldingCache");

Mal sehen, was hier passiert, um mehr zu erfahren. Zunächst findet Ignite den Speicherbereich, in dem der Cache gespeichert ist.

Dann wird die B + -Baumindex-Seite basierend auf dem Schlüssel-Hashcode lokalisiert.

Wenn der Index existiert, wird eine Datenseite des entsprechenden Schlüssels gefunden.

**  Wenn der Index NULL ist, erstellt die Plattform den neuen Dateneintrag mit dem angegebenen Schlüssel. **

Als Nächstes fügen wir einige __Employee__-Objekte hinzu:

[source,java,gutter:,true]

cache.put(1, new Employee(1, "John", true)); cache.put(2, new Employee(2, "Anna", false)); cache.put(3, new Employee(3, "George", true));

Wieder sucht der dauerhafte Speicher nach dem Speicherbereich, zu dem der Cache gehört. Basierend auf dem Cache-Schlüssel befindet sich die Indexseite in einer B-Baumstruktur.

**  Wenn die Indexseite nicht vorhanden ist, wird eine neue angefordert und der Baumstruktur hinzugefügt. **

Als Nächstes wird der Indexseite eine Datenseite zugewiesen.

Um den Mitarbeiter aus dem Cache zu lesen, verwenden wir einfach den Schlüsselwert:

[source,java,gutter:,true]

Employee employee = cache.get(1);

[[streaming__support]]

====  **  6.2. Streaming-Unterstützung **

Im Arbeitsspeicher bietet das Daten-Streaming einen alternativen Ansatz für die auf Daten- und Dateisystemen basierenden Datenverarbeitungsanwendungen. Die Streaming-API teilt den Datenstrom mit hoher Last in mehrere Stufen auf und leitet sie zur Verarbeitung weiter.

Wir können unser Beispiel ändern und die Daten aus der Datei streamen. Zuerst definieren wir einen Datenstreamer:

[source,java,gutter:,true]

IgniteDataStreamer<Integer, Employee> streamer = ignite .dataStreamer(cache.getName());

Als Nächstes können wir einen Stream-Transformator registrieren, um die empfangenen Mitarbeiter als beschäftigt zu markieren:

[source,java,gutter:,true]

streamer.receiver(StreamTransformer.frome, arg) → { Employee employee = e.getValue(); employee.setEmployed(true); e.setValue(employee); return employee; };

Als letzten Schritt werden die Zeilen der Datei __employees.txt__ durchlaufen und in Java-Objekte konvertiert:

[source,java,gutter:,true]

Path path = Paths.get(IgniteStream.class.getResource("employees.txt") .toURI()); Gson gson = new Gson(); Files.lines(path) .forEach(l → streamer.addData( employee.getId(), gson.fromJson(l, Employee.class)));

**  Mit __streamer.addData () __ fügen Sie die Mitarbeiterobjekte in den Stream ein. **

[[sql__support]]

===  **  7. SQL-Unterstützung **

**  Die Plattform bietet eine speicherzentrierte, fehlertolerante SQL-Datenbank. **

Wir können uns entweder mit der reinen SQL-API oder mit JDBC verbinden. Die SQL-Syntax hier ist ANSI-99, daher werden alle Standardaggregationsfunktionen in den Abfragen, DML- und DDL-Sprachoperationen unterstützt.

====  **  7.1. JDBC **

Um praktischer zu werden, erstellen wir eine Tabelle mit Mitarbeitern und fügen einige Daten hinzu.

Zu diesem Zweck registrieren wir einen JDBC-Treiber und öffnen als nächsten Schritt eine Verbindung:

[source,java,gutter:,true]

Class.forName("org.apache.ignite.IgniteJdbcThinDriver"); Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1/");

Mit Hilfe des Standard-DDL-Befehls füllen wir die Tabelle __Employee__ auf:

[source,java,gutter:,true]

sql.executeUpdate("CREATE TABLE Employee ("
" id LONG PRIMARY KEY, name VARCHAR, isEmployed tinyint(1)) "
" WITH \"template=replicated\"");

Nach dem WITH-Schlüsselwort können wir die Cache-Konfigurationsvorlage festlegen.

Hier verwenden wir das __REPLICATED__. **  Der Vorlagenmodus ist standardmäßig __PARTITIONED__ ** . **  Um die Anzahl der Kopien der Daten anzugeben, können Sie hier auch den __BACKUPS__ **  -Parameter angeben, der standardmäßig 0 ist.

Dann lassen Sie uns einige Daten mit der INSERT DML-Anweisung zusammenfassen:

[source,java,gutter:,true]

PreparedStatement sql = conn.prepareStatement( "INSERT INTO Employee (id, name, isEmployed) VALUES (?, ?, ?)");

sql.setLong(1, 1); sql.setString(2, "James"); sql.setBoolean(3, true); sql.executeUpdate();

Danach wählen wir die Datensätze aus:

[source,java,gutter:,true]

ResultSet rs = sql.executeQuery("SELECT e.name, e.isEmployed " + " FROM Employee e " + " WHERE e.isEmployed = TRUE ")

====  **  7.2. Objekte abfragen **

**  Es ist auch möglich, eine Abfrage über im Cache gespeicherte Java-Objekte durchzuführen ** . Ignite behandelt Java-Objekt als separaten SQL-Datensatz:

[source,java,gutter:,true]

IgniteCache<Integer, Employee> cache = ignite.cache("baeldungCache");

SqlFieldsQuery sql = new SqlFieldsQuery( "select name from Employee where isEmployed = 'true'");

QueryCursor<List<?>> cursor = cache.query(sql);

for (List<?> row : cursor) { //do something with the row }

===  **  8. Zusammenfassung**

In diesem Lernprogramm haben wir uns kurz das Apache Ignite-Projekt angesehen. In diesem Handbuch werden die Vorteile der Plattform gegenüber anderen Simial-Produkten wie Leistungssteigerung, Haltbarkeit und leichte APIs hervorgehoben.

Infolgedessen **  haben wir gelernt, wie Sie die Daten mithilfe der SQL-Sprache und der Java-API speichern, abrufen und streamen können.

Wie üblich ist der vollständige Code für diesen Artikel verfügbar: https://github.com/eugenp/tutorials/tree/master/libraries-data/[over auf GitHub].