Un guide pour 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 mise en cache ou pour le traitement de données en mémoire.

La plate-forme utilise la mémoire en tant que couche de stockage et présente donc un taux de performance impressionnant. En termes simples, ** il s’agit de l’une des plateformes de traitement de données atomiques les plus rapides actuellement en production.

** 2. Installation et configuration

**

Commencez par consulter la page getting started pour la configuration initiale et les instructions d’installation.

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

<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 est le seule dépendance obligatoire pour le projet ** . Comme nous voulons aussi interagir avec le SQL, ignite-indexing est aussi ici.

$\{ignite.version } est la dernière version d’Apache Ignite.

Dans la dernière étape, nous démarrons le noeud 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.

[[architecture]]

===  3. Architecture de la mémoire

**  La plate-forme est basée sur une architecture à 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 qu'aucune conversion supplémentaire des données n'est nécessaire lors du déplacement 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__.

Il est utile de lire, d’écrire une page et d’attribuer un identifiant de page. **  Dans la mémoire, Ignite associe des pages à __Memory Buffers__ ** .

[[pages]]

===  **  4. Pages de mémoire **

Une page peut avoir les états suivants:

**  Déchargé - pas de tampon de page chargé en mémoire

**  Clear - le tampon de page est chargé et synchronisé avec les données de

disque
**  Durty - le tampon de page contient une donnée différente de celle

dans le disque
**  Sale in checkpoint - une autre modification commence avant la

le premier persiste sur le disque. Ici, un point de contrôle commence et __PageMemory__ conserve deux mémoires tampons pour chaque page.

**  La mémoire durable alloue localement un segment de mémoire appelé __Data Region __. **  Par défaut, il a une capacité de 20% de la mémoire du cluster. La configuration de régions multiples 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 enregistre les données dans 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 la vie**

**  Chaque nœud Ignite s'exécute sur une seule instance JVM ** . Cependant, il est possible de configurer plusieurs nœuds Ignite s’exécutant dans un même processus JVM.

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

**  __BEFORE__NODE__START__ - avant le démarrage du noeud Ignite

**  __AFTER__NODE__START__ - se déclenche juste après le démarrage du noeud Ignite

**  __BEFORE__NODE__STOP__ - avant de lancer l'arrêt du noeud

**  __AFTER__NODE__STOP__ - après l'arrêt du noeud Ignite

Pour démarrer un noeud Ignite par défaut:

[source,java,gutter:,true]

Ignite ignite = Ignition.start();

Ou à partir d'un fichier de configuration:

[source,java,gutter:,true]

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

[source,java,gutter:,true]

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énement de cycle de vie pour effectuer des actions avant ou après le démarrage/l'arrêt du nœud.

Pour cela, nous passons l'instance de configuration avec __CustomLifecycleBean__ à la méthode de démarrage:

[source,java,gutter:,true]

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

[[data__grid]]

===  6. Grille de données en mémoire

**  Ignite data grid est un stockage distribué clé-valeur ** , très familier avec __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.

Il peut améliorer considérablement les performances du logiciel tiers, tel que NoSql, les bases de données RDMS en tant que couche supplémentaire pour la mise en cache.

[[caching__support]]

====  **  6.1. Support de mise en cache **

**  L'API d'accès aux données est basée sur la spécification JCache JSR 107. **

Par exemple, créons un cache en utilisant une configuration de modèle:

[source,java,gutter:,true]

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

Voyons ce qui se passe ici pour plus de détails. Tout d'abord, Ignite trouve la région de la mémoire où le cache est stocké.

Ensuite, la page d'index de l'arborescence B + sera localisée en fonction du code de hachage de la clé.

Si l'index existe, une page de données de la clé correspondante sera localisée.

**  Lorsque l'index est NULL, la plateforme crée la nouvelle entrée de données en utilisant la clé donnée. **

Ajoutons ensuite quelques objets __Employee__:

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

Là encore, la mémoire durable recherchera la région de mémoire à laquelle appartient le cache. Sur la base de la clé de cache, la page d'index sera située dans une arborescence B +.

**  Lorsque la page d’index n’existe pas, une nouvelle page est demandée et ajoutée à l’arbre. **

Ensuite, une page de données est assignée à la page d'index.

Pour lire l'employé à partir du cache, nous utilisons simplement la valeur de clé:

[source,java,gutter:,true]

Employee employee = cache.get(1);

[[streaming__support]]

====  **  6.2. Support en streaming **

En mémoire en continu, la diffusion de données fournit une approche alternative pour les applications de traitement de données basées sur le disque et le système de fichiers. **  L'API Streaming divise le flux de données à forte charge en plusieurs étapes et les achemine pour traitement ** .

Nous pouvons modifier notre exemple et diffuser les données du fichier. Tout d'abord, nous définissons un streamer de données:

[source,java,gutter:,true]

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

Ensuite, nous pouvons enregistrer un transformateur de flux pour marquer les employés reçus comme employés:

[source,java,gutter:,true]

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

Enfin, nous parcourons les lignes du fichier __employees.txt__ et les convertissons en objets Java:

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

**  Avec __streamer.addData () __, placez les objets employés dans le flux. **

[[sql__support]]

===  **  7. Support SQL **

**  La plate-forme fournit une base de données SQL axée sur la mémoire et tolérante aux pannes. **

Nous pouvons nous connecter soit avec une API SQL pure, soit avec JDBC. La syntaxe SQL est ici ANSI-99; toutes les fonctions d'agrégation standard des requêtes, opérations DML et langage DDL, sont donc prises en charge.

====  **  7.1. JDBC **

Pour plus de commodité, créons un tableau d’employés et ajoutez-y des données.

Pour cela, **  nous enregistrons un pilote JDBC et ouvrons une connexion **  à l'étape suivante:

[source,java,gutter:,true]

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

À l'aide de la commande DDL standard, nous renseignons la table __Employee__:

[source,java,gutter:,true]

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

Après le mot-clé WITH, nous pouvons définir le modèle de configuration du cache.

Ici nous utilisons le __REPLICATED__. **  Par défaut, le mode modèle est __PARTITIONED__ ** . **  Pour spécifier le nombre de copies des données, nous pouvons également spécifier le paramètre __BACKUPS__ ** , qui est 0 par défaut.

Ensuite, ajoutons quelques données en utilisant l’instruction INSERT DML:

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

Ensuite, nous sélectionnons les enregistrements:

[source,java,gutter:,true]

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

====  **  7.2. Interroger les objets **

**  Il est également possible d’effectuer une requête sur les objets Java stockés dans le cache ** . Ignite traite l'objet Java comme un enregistrement SQL distinct:

[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. Résumé**

Dans ce tutoriel, nous avons examiné rapidement le projet Apache Ignite. Ce guide met en évidence les avantages de la plate-forme par rapport aux autres produits simial, tels que les gains de performance, la durabilité, les API légères.

En conséquence, **  nous avons appris à utiliser le langage SQL et l’API Java pour stocker, récupérer, diffuser en continu 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 https://github.com/eugenp/tutorials/tree/master/libraries-data/[over sur GitHub].