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.