Utilisation de Hazelcast comme grille de données en mémoire distribuée et cache mémoire distribué

Introduction à Hazelcast

Hazelcast est une plateforme open-source de grille de données en mémoire (IMDG). Elle offre un stockage en mémoire distribué, élastique et hautement disponible pour les applications. Hazelcast se présente sous forme de bibliothèque Java embarquée, sans dépendances externes, permettant une intégration facile dans des projets existants.

Documentation officielle : https://docs.hazelcast.com/hazelcast/5.3/

Concepts de la Grille de Données en Mémoire

Une IMDG répartit les données sur plusieurs nœuds d'un cluster, permettant un accès rapide et une tolérance aux pannes. Hazelcast propose des abstractions distribuées familières telles que Map, Queue, Set et Lock.

Pour le cache distribué, Hazelcast partitionne automatiquement les données et les réplique entre les membres du cluster pour assurer la redondance.

Partitionnement des Données

Par défaut, Hazelcast utilise 271 partitions. Lorsqu'un membre rejoint le cluster, une partie des partitions primaires et de sauvegarde lui est attribuée de manière équitable via un algorithme de hachage cohérent.

Une table de partitionnement maintient la localisation de chaque partition dans le cluster, permettant à tout membre de savoir où se trouvent les données.

Configuration et Déploiement

Dépendances Maven

<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast</artifactId>
    <version>5.3.6</version>
</dependency>

Création d'un Cluster

Par défaut, les membres se découvrent automatiquement via multicast sur le même réseau.

import com.hazelcast.config.Config;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import java.util.Map;
import java.util.Queue;

public class ClusterInitializer {
    public static void main(String[] args) {
        Config clusterConfig = new Config();
        HazelcastInstance node = Hazelcast.newHazelcastInstance(clusterConfig);

        Map<Long, String> userMap = node.getMap("utilisateurs");
        userMap.put(1L, "Pierre");
        userMap.put(2L, "Marie");
        System.out.println("Utilisateur clé 1 : " + userMap.get(1L));

        Queue<String> fileAttente = node.getQueue("commandes");
        fileAttente.offer("Commande001");
        System.out.println("Premier élément : " + fileAttente.poll());
    }
}

Exécuter cette classe plusieurs fois crée un cluster. Chaque instance devient membre.

Groupes de Clusters

Il est possible d'isoler des clusters en leur attribuant des noms distincts.

Config configProd = new Config();
configProd.setClusterName("production");

Config configDev = new Config();
configDev.setClusterName("development");

HazelcastInstance prodNode = Hazelcast.newHazelcastInstance(configProd);
HazelcastInstance devNode1 = Hazelcast.newHazelcastInstance(configDev);
HazelcastInstance devNode2 = Hazelcast.newHazelcastInstance(configDev);

Configuration Réseau

Config customConfig = new Config();
customConfig.getNetworkConfig()
    .setPort(5701)
    .setPortAutoIncrement(true)
    .setPortCount(10);

Hazelcast supporte également la découverte via TCP/IP, AWS, Kubernetes, Azure, etc.

Structures de Données Distribuées

IMap - Carte Distribuée

IMap étend ConcurrentMap et offre des opérations thread-safe avec partitionnement et réplication.

import com.hazelcast.config.*;
import java.util.concurrent.TimeUnit;

public class CacheDistribue {
    public static void main(String[] args) {
        Config config = new Config();
        config.setClusterName("monCluster");

        MapConfig configMap = new MapConfig();
        configMap.setName("cacheProduits");
        configMap.setBackupCount(1);
        configMap.setAsyncBackupCount(1);
        configMap.setTimeToLiveSeconds(300);

        EvictionConfig configEviction = new EvictionConfig();
        configEviction.setEvictionPolicy(EvictionPolicy.LRU);
        configEviction.setSize(5000);
        configMap.setEvictionConfig(configEviction);

        config.addMapConfig(configMap);

        HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
        IMap<String, Object> cache = instance.getMap("cacheProduits");

        cache.put("ref123", "Produit A", -1, null); // Pas d'expiration
        cache.put("ref456", "Produit B", 60, TimeUnit.SECONDS); // Expiration en 60s
        
        Object valeur = cache.get("ref123");
        cache.lock("ref456");
        try {
            // Opération critique
        } finally {
            cache.unlock("ref456");
        }
        
        cache.replace("ref123", "Produit A", "Produit A Modifié");
    }
}

IQueue - File d'Attente Distribuée

import com.hazelcast.core.IQueue;
import java.util.concurrent.TimeUnit;

public class FileDistribuee {
    public static void main(String[] args) throws InterruptedException {
        HazelcastInstance instance = Hazelcast.newHazelcastInstance();
        IQueue<String> taches = instance.getQueue("tachesTraitement");
        
        taches.put("Tache_1");
        String tache = taches.take();
        
        boolean insere = taches.offer("Tache_2", 5, TimeUnit.SECONDS);
        String tachePoll = taches.poll(3, TimeUnit.SECONDS);
    }
}

MultiMap - Carte à Valeurs Multiples

import com.hazelcast.core.MultiMap;
import java.util.Collection;

public class CarteMultiValeurs {
    public static void main(String[] args) {
        HazelcastInstance instance = Hazelcast.newHazelcastInstance();
        MultiMap<String, Integer> scores = instance.getMultiMap("scoresJeux");
        
        scores.put("joueur1",与被插入 1500);
        scores.put("joueur1", 1700);
        scores.put("joueur2", 1200);
        
        for (String joueur : scores.keySet()) {
            Collection<Integer> points = scores.get(joueur);
            System.out.println(joueur + " -> " + points);
        }
    }
}

ISet et IList - Ensembles et Listes Distribués

// Ensemble distribué
HazelcastInstance hz = Hazelcast.newHazelcastInstance();
ISet<String> villes = hz.getSet("villesVisitees");
villes.add("Lyon");
villes.add("Marseille");

// Liste distribuée
IList<String> historique = hz.getList("historiqueActions");
historique.add("Action1");
historique.add("Action2");

Autres Structures

Hazelcast propose également : RingBuffer, Topic (pub/sub), FencedLock (verrou distribué), IAtomicLong, ISemaphore, ICountDownLatch, FlakeIdGenerator, etc.

Considérations de Performance

Les performances dépendent de facteurs comme la latence réseau, la configuration du cluster et les caractéristiques des données. Hazelcast est conçu pour des scénarios où la cohérence des données et la facilité d'intégration Java sont prioritaires.

Pour les charges de travail nécessitant une très haute performance en lecture/écriture, des optimisations de configuration (format mémoire NATIVE, ajustement des backup counts, partitionnement) peuvent être appliquées.

Étiquettes: Hazelcast IMDG Cache_distribué Java NoSQL

Publié le 10 octobre à 07h50