Un guide sur Apache Ignite

1. Introduction

Apache Ignite est une plate-forme distribuée open source centrée sur la mémoire. Nous pouvons l'utiliser comme base de données, système de cache ou pour le traitement des données en mémoire.

La plate-forme utilise la mémoire comme couche de stockage et a donc un taux de performance impressionnant. En termes simples, il s'agit de l'une des plates-formes de traitement de données atomiques les plus rapides actuellement utilisées en production.

2. Installation et configuration

Pour commencer, consultez la page de démarrage pour les instructions de configuration initiale et d'installation.

Les dépendances Maven pour l'application que nous allons construire:

 org.apache.ignite ignite-core ${ignite.version}   org.apache.ignite ignite-indexing ${ignite.version} 

ignite-core est la seule dépendance obligatoire pour le projet . Comme nous voulons également interagir avec le SQL, l' indexation ignite est également là. $ {ignite.version} est la dernière version d'Apache Ignite.

Comme dernière étape, nous démarrons le nœud Ignite:

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]

La sortie de la console ci-dessus montre que nous sommes prêts à partir.

3. Architecture de la mémoire

La plate-forme est basée sur une architecture de mémoire durable . Cela permet de stocker et de traiter les données à la fois sur disque et en mémoire. Il augmente les performances en utilisant efficacement les ressources RAM du cluster.

Les données en mémoire et sur le disque ont la même représentation binaire. Cela signifie aucune conversion supplémentaire des données lors du passage d'une couche à une autre.

L'architecture de mémoire durable se divise en blocs de taille fixe appelés pages. Les pages sont stockées en dehors du tas Java et organisées dans une RAM. Il a un identifiant unique: FullPageId .

Les pages interagissent avec la mémoire à l'aide de l' abstraction PageMemory .

Cela permet de lire, d'écrire une page, ainsi que d'allouer un identifiant de page. À l'intérieur de la mémoire, Ignite associe des pages à des tampons mémoire .

4. Pages mémoire

Une page peut avoir les états suivants:

  • Déchargé - aucun tampon de page chargé en mémoire
  • Effacer - le tampon de page est chargé et synchronisé avec les données sur le disque
  • Durty - le tampon de page contient des données différentes de celles du disque
  • Sale au point de contrôle - une autre modification commence avant que la première ne persiste sur le disque. Ici, un point de contrôle démarre et PageMemory conserve deux tampons de mémoire pour chaque page.

La mémoire durable alloue localement un segment de mémoire appelé région de données . Par défaut, il a une capacité de 20% de la mémoire du cluster. La configuration de plusieurs régions permet de conserver les données utilisables dans une mémoire.

La capacité maximale de la région est un segment de mémoire. C'est une mémoire physique ou un tableau d'octets continu.

Pour éviter les fragmentations de mémoire, une seule page contient plusieurs entrées de valeur-clé . Chaque nouvelle entrée sera ajoutée à la page la plus optimale. Si la taille de la paire clé-valeur dépasse la capacité maximale de la page, Ignite stocke les données sur plusieurs pages. La même logique s'applique à la mise à jour des données.

Les index SQL et de cache sont stockés dans des structures appelées arbres B +. Les clés de cache sont classées par leurs valeurs de clé.

5. Cycle de vie

Chaque nœud Ignite s'exécute sur une seule instance JVM . Cependant, il est possible de configurer pour que plusieurs nœuds Ignite s'exécutent dans un seul processus JVM.

Passons en revue les types d'événements du cycle de vie:

  • BEFORE_NODE_START - avant le démarrage du nœud Ignite
  • AFTER_NODE_START - se déclenche juste après le démarrage du nœud Ignite
  • BEFORE_NODE_STOP - avant de lancer l'arrêt du nœud
  • AFTER_NODE_STOP - après l'arrêt du nœud Ignite

Pour démarrer un nœud Ignite par défaut:

Ignite ignite = Ignition.start();

Ou à partir d'un fichier de configuration:

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

Au cas où nous aurions besoin de plus de contrôle sur le processus d'initialisation, il existe un autre moyen à l'aide de l' interface LifecycleBean :

public class CustomLifecycleBean implements LifecycleBean { @Override public void onLifecycleEvent(LifecycleEventType lifecycleEventType) throws IgniteException { if(lifecycleEventType == LifecycleEventType.AFTER_NODE_START) { // ... } } }

Ici, nous pouvons utiliser les types d'événements du cycle de vie pour effectuer des actions avant ou après le démarrage / l'arrêt du nœud.

Pour cela, nous transmettons l'instance de configuration avec le CustomLifecycleBean à la méthode de démarrage:

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

6. Grille de données en mémoire

Ignite data grid est un stockage clé-valeur distribué , très familier à HashMap partitionné . Il est mis à l'échelle horizontalement. Cela signifie que nous ajoutons plus de nœuds de cluster, plus de données sont mises en cache ou stockées en mémoire.

It can provide significant performance improvement to the 3rd party software, like NoSql, RDMS databases as an additional layer for caching.

6.1. Caching Support

The data access API is based on JCache JSR 107 specification.

As an example, let's create a cache using a template configuration:

IgniteCache cache = ignite.getOrCreateCache( "baeldingCache");

Let's see what's happening here for more details. First, Ignite finds the memory region where the cache stored.

Then, the B+ tree index Page will be located based on the key hash code. If the index exists, a data Page of the corresponding key will be located.

When the index is NULL, the platform creates the new data entry by using the given key.

Next, let's add some Employee objects:

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

Again, the durable memory will look for the memory region where the cache belongs. Based on the cache key, the index page will be located in a B+ tree structure.

When the index page doesn't exist, a new one is requested and added to the tree.

Next, a data page is assigning to the index page.

To read the employee from the cache, we just use the key value:

Employee employee = cache.get(1);

6.2. Streaming Support

In memory data streaming provides an alternative approach for the disk and file system based data processing applications. The Streaming API splits the high load data flow into multiple stages and routes them for processing.

We can modify our example and stream the data from the file. First, we define a data streamer:

IgniteDataStreamer streamer = ignite .dataStreamer(cache.getName());

Next, we can register a stream transformer to mark the received employees as employed:

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

As a final step, we iterate over the employees.txt file lines and convert them into Java objects:

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

With the use of streamer.addData() put the employee objects into the stream.

7. SQL Support

The platform provides memory-centric, fault-tolerant SQL database.

We can connect either with pure SQL API or with JDBC. SQL syntax here is ANSI-99, so all the standard aggregation functions in the queries, DML, DDL language operations are supported.

7.1. JDBC

To get more practical, let's create a table of employees and add some data to it.

For that purpose, we register a JDBC driver and open a connection as a next step:

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

With the help of the standard DDL command, we populate the Employee table:

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

After the WITH keyword, we can set the cache configuration template. Here we use the REPLICATED. By default, the template mode is PARTITIONED. To specify the number of copies of the data we can also specify BACKUPS parameter here, which is 0 by default.

Then, let's add up some data by using INSERT DML statement:

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(); // add the rest 

Afterward, we select the records:

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

7.2. Query the Objects

It's also possible to perform a query over Java objects stored in the cache. Ignite treats Java object as a separate SQL record:

IgniteCache cache = ignite.cache("baeldungCache"); SqlFieldsQuery sql = new SqlFieldsQuery( "select name from Employee where isEmployed = 'true'"); QueryCursor
    
      cursor = cache.query(sql); for (List row : cursor) { // do something with the row }
    

8. Summary

In this tutorial, we had a quick look at Apache Ignite project. This guide highlights the advantages of the platform over other simial products such as performance gains, durability, lightweight APIs.

En conséquence, nous avons appris à utiliser le langage SQL et l'API Java pour stocker, récupérer, diffuser les données à l'intérieur de la grille de persistance ou en mémoire.

Comme d'habitude, le code complet de cet article est disponible à l'adresse over sur GitHub.