Hazelcast
GitHub Overview
hazelcast/hazelcast
Hazelcast is a unified real-time data platform combining stream processing with a fast data store, allowing customers to act instantly on data-in-motion for real-time insights.
Topics
Star History
Cache Library
Hazelcast
Overview
Hazelcast is a Java-based open-source distributed in-memory data grid platform that integrates distributed caching, distributed computing, and distributed data storage functionality to provide high availability and scalability. While using standard Java Map interfaces, it automatically distributes and replicates data across multiple JVM instances, ensuring partition tolerance and data consistency.
Details
Hazelcast is a platform that reduces dependency on traditional relational databases and file systems, achieving significant performance improvements through in-memory data processing. In distributed systems, it enables fast data access and processing by leveraging data locality and minimizing network calls.
Key Distributed Data Structures
- Map: Key-value pairs distributed across the cluster, supporting SQL queries, WAN replication, and Near Cache
- Cache: Hazelcast's JCache specification-compliant implementation
- Queue/Priority Queue: Item addition and removal with FIFO ordering or configurable ordering
- Set/List: Distributed collections without duplicates and distributed lists that preserve order
- MultiMap: Special Map that can store multiple values for a single key
- Replicated Map: Key-value pairs fully replicated on each member
- Topic/Reliable Topic: Message delivery to multiple subscribers (pub/sub)
Enterprise Features (CP Data Structures)
- Atomic Long/Reference: Atomic value operations in distributed environments
- Countdown Latch: Gatekeeper for concurrent activities
- Semaphore: Creates permits for controlling thread counts
Pros and Cons
Pros
- High Scalability: Linear performance improvement through node addition
- Fault Tolerance: High availability through automatic failover and data replication
- Standard API Compatibility: Compatibility with existing Java Collection framework APIs
- Data Locality: Reduces network load by executing operations on the same member for the same key
- Real-time Processing: Immediate notification of data changes through event listeners
- Rich Ecosystem: Integration with Kubernetes, Spring Boot, Apache Kafka, etc.
Cons
- Memory Consumption: Increased memory requirements when handling large amounts of data
- Network Dependency: Risk of temporary service interruption during network partitions
- Complexity: Complexity of configuration and operation inherent to distributed systems
- Java-Specific: Usage scope mainly limited to the Java ecosystem
Reference Links
Code Examples
Basic Hazelcast Instance Creation and Distributed Map Operations
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;
// Creating Hazelcast instance
HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance();
// Getting distributed Map
IMap<String, String> map = hazelcast.getMap("my-distributed-map");
// Writing data
map.put("1", "John");
map.put("2", "Mary");
map.put("3", "Jane");
// Reading data
System.out.println(map.get("1")); // John
System.out.println(map.get("2")); // Mary
System.out.println(map.get("3")); // Jane
Cluster Configuration and Network Settings
import com.hazelcast.config.Config;
import com.hazelcast.config.NetworkConfig;
import com.hazelcast.config.JoinConfig;
Config config = new Config();
config.setClusterName("my-cluster");
// Network configuration
NetworkConfig networkConfig = config.getNetworkConfig();
networkConfig.setPort(5701);
networkConfig.setPortAutoIncrement(true);
// Cluster join configuration
JoinConfig joinConfig = networkConfig.getJoin();
joinConfig.getMulticastConfig().setEnabled(false);
joinConfig.getTcpIpConfig()
.setEnabled(true)
.addMember("192.168.1.100")
.addMember("192.168.1.101");
HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance(config);
Distributed Queue and Messaging
import com.hazelcast.collection.IQueue;
import com.hazelcast.topic.ITopic;
// Using distributed queue
IQueue<String> queue = hazelcast.getQueue("my-queue");
queue.offer("Hello");
queue.offer("World");
String item = queue.poll(); // "Hello"
// Publish-Subscribe messaging
ITopic<String> topic = hazelcast.getTopic("my-topic");
// Registering message listener
topic.addMessageListener(message -> {
System.out.println("Received: " + message.getMessageObject());
});
// Sending message
topic.publish("Hello, Cluster!");
Distributed Execution Service
import com.hazelcast.core.IExecutorService;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
// Getting distributed execution service
IExecutorService executor = hazelcast.getExecutorService("my-executor");
// Task definition
Callable<Integer> task = () -> {
return 100 + 23;
};
// Executing task
Future<Integer> future = executor.submit(task);
Integer result = future.get(); // 123
// Executing task on specific member
executor.executeOnKeyOwner(task, "my-key");
Near Cache Configuration
import com.hazelcast.config.NearCacheConfig;
import com.hazelcast.config.MapConfig;
Config config = new Config();
// Near Cache configuration
NearCacheConfig nearCacheConfig = new NearCacheConfig();
nearCacheConfig.setName("my-map-near-cache");
nearCacheConfig.setInMemoryFormat(InMemoryFormat.BINARY);
nearCacheConfig.setInvalidateOnChange(true);
nearCacheConfig.setTimeToLiveSeconds(0);
nearCacheConfig.setMaxIdleSeconds(60);
// Adding Near Cache to Map configuration
MapConfig mapConfig = new MapConfig("my-map");
mapConfig.setNearCacheConfig(nearCacheConfig);
config.addMapConfig(mapConfig);
HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance(config);
Efficient Data Processing with Entry Processor
import com.hazelcast.map.EntryProcessor;
// Custom entry processor
public class IncrementProcessor implements EntryProcessor<String, Integer, Integer> {
@Override
public Integer process(Map.Entry<String, Integer> entry) {
Integer currentValue = entry.getValue();
if (currentValue == null) {
currentValue = 0;
}
Integer newValue = currentValue + 1;
entry.setValue(newValue);
return newValue;
}
}
// Using entry processor
IMap<String, Integer> map = hazelcast.getMap("counters");
map.put("counter1", 5);
// Efficient increment operation (reduces network load)
Integer result = map.executeOnKey("counter1", new IncrementProcessor());
System.out.println("New value: " + result); // 6
Event Listeners and Data Change Notifications
import com.hazelcast.core.EntryEvent;
import com.hazelcast.map.MapListener;
// Map listener implementation
MapListener listener = new MapListener() {
@Override
public void entryAdded(EntryEvent event) {
System.out.println("Added: " + event.getKey() + " = " + event.getValue());
}
@Override
public void entryUpdated(EntryEvent event) {
System.out.println("Updated: " + event.getKey() +
" old=" + event.getOldValue() +
" new=" + event.getValue());
}
@Override
public void entryRemoved(EntryEvent event) {
System.out.println("Removed: " + event.getKey());
}
};
// Registering listener
IMap<String, String> map = hazelcast.getMap("my-map");
map.addEntryListener(listener, true);