I am learning how the different Hazelcast cache topologies work. I use the latest 5.5.0
maven dependency and I use always and only Java configuration, and no XML config is used.
I have a problem with the Map-ID hazelcastClient.getMap("name")
and the Near-Cahche-Configuration name new NearCacheConfig("name")
.
The doc here says this:
The Near Cache on the client side must have the same name as the data structure on the member for which this Near Cache is being created. You can use wildcards, so in this example mostlyRead* would also match the map mostlyReadMap.
It is clear that Near Cache Config lives on the client side and the map-id is used to identify the distributed map within the Hazelcast cluster.
But for me the wildcards do not want to work and my demo only works properly if the near-cache-configuration name equals with the map-id:
... new NearCacheConfig("counter")
... hazelcastClient.getMap("counter")
I tried the following combinations but non of them works, my near-cache-config is not used:
new NearCacheConfig("counter)
andhazelcastClient.getMap("counterId)
new NearCacheConfig("counterId)
andhazelcastClient.getMap("counter)
This is my test code:
public class HazelcastConfiguration {
// THE FOLLOWING TWO VALUES MUST BE IDENTICAL
// e.g. "counter-config" and "counter" DOES NOT WORK
public static final String NEAR_CACHE_CONFIG_NAME = "counter";
public static final String COUNTER_MAP_ID = "counter";
private static final String HZ_CLUSTER_NAME = "gombi-dev";
private static final String HZ_CLUSTER_ADDRESS_1 = "localhost:13063";
private static final String HZ_CLUSTER_ADDRESS_2 = "localhost:13073";
public static HazelcastInstance getHazelcastInstance() {
NearCacheConfig nearCacheConfigForCounterMap = new NearCacheConfig(NEAR_CACHE_CONFIG_NAME)
.setInMemoryFormat(InMemoryFormat.BINARY)
.setTimeToLiveSeconds(30)
.setMaxIdleSeconds(10)
.setEvictionConfig(new EvictionConfig()
.setEvictionPolicy(EvictionPolicy.LRU)
.setSize(1000));
ClientConfig clientConfig = new ClientConfig();
clientConfig.setClusterName(HZ_CLUSTER_NAME);
clientConfig.getNetworkConfig().getAddresses().add(HZ_CLUSTER_ADDRESS_1);
clientConfig.getNetworkConfig().getAddresses().add(HZ_CLUSTER_ADDRESS_2);
clientConfig.addNearCacheConfig(nearCacheConfigForCounterMap);
return HazelcastClient.newHazelcastClient(clientConfig);
}
}
Then my cache reader demo:
public class NearCacheReader {
public static void main(String[] args) {
String username = "zappee";
String key = MapKeyGenerator.getKey(username);
HazelcastInstance hazelcastClient = HazelcastConfiguration.getHazelcastInstance();
TimerTask task = new TimerTask() {
@Override
public void run() {
// nearCache will never be null
IMap<String, Integer> nearCache = hazelcastClient.getMap(HazelcastConfiguration.COUNTER_MAP_ID);
Integer value = nearCache.get(key);
if (Objects.isNull(value)) {
System.out.printf(
"[%s] near-cache entry miss: {username: \"%s\"}%n",
LocalTimeConverter.nowAsString(),
username);
} else {
System.out.printf(
"[%s] near-cache entry hit: {username: \"%s\", value: %s}%n",
LocalTimeConverter.nowAsString(),
username,
value);
}
}
};
// Schedule the timer task to run after 1 second
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 1000);
}
}
And my cache updater demo:
public class NearCacheUpdater {
public static void main(String[] args) {
String username = "zappee";
String key = MapKeyGenerator.getKey(username);
HazelcastInstance hazelcastClient = HazelcastConfiguration.getHazelcastInstance();
IMap<String, Integer> nearCache = hazelcastClient.getMap(HazelcastConfiguration.COUNTER_MAP_ID);
nearCache.put(key, 1);
TimerTask task = new TimerTask() {
@Override
public void run() {
int value = nearCache.get(key);
value++;
nearCache.put(key, value);
System.out.printf(
"[%s] value in the cache has been updated: {username: \"%s\", new-value: %s}\n",
LocalTimeConverter.nowAsString(),
username,
value);
}
};
// Schedule the timer task to run after 1 second
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 1000);
}
}
This is the output log if the NEAR_CACHE_CONFIG_NAME
and COUNTER_MAP_ID
are equals. First start the reader, then later the updater. Here I can see clearly that the value comes from the local cache and it is refreshed in every 10 second:
[23:27:32] near-cache entry miss: {username: "zappee"}
[23:27:33] near-cache entry miss: {username: "zappee"}
...
[23:27:57] near-cache entry miss: {username: "zappee"}
[23:27:58] near-cache entry hit: {username: "zappee", value: 12}
[23:27:59] near-cache entry hit: {username: "zappee", value: 12}
...
[23:28:07] near-cache entry hit: {username: "zappee", value: 12}
[23:28:08] near-cache entry hit: {username: "zappee", value: 22}
...
[23:28:17] near-cache entry hit: {username: "zappee", value: 22}
[23:28:18] near-cache entry hit: {username: "zappee", value: 32}
...
And the updater log, which only updates the cache value every second:
[23:27:47] value in the cache has been updated: {username: "zappee", new-value: 2}
[23:27:48] value in the cache has been updated: {username: "zappee", new-value: 3}
[23:27:49] value in the cache has been updated: {username: "zappee", new-value: 4}
...
[23:28:28] value in the cache has been updated: {username: "zappee", new-value: 43}
...
But if the NEAR_CACHE_CONFIG_NAME
and COUNTER_MAP_ID
are only partially equals, the near cache configuration does not work as I see it and according to the log the value is always read from the Hazelcast cluster, not from the local cache:
[23:37:01] near-cache entry miss: {username: "zappee"}
[23:37:02] near-cache entry miss: {username: "zappee"}
...
[23:37:09] near-cache entry miss: {username: "zappee"}
[23:37:10] near-cache entry hit: {username: "zappee", value: 2}
[23:37:11] near-cache entry hit: {username: "zappee", value: 3}
[23:37:12] near-cache entry hit: {username: "zappee", value: 4}
[23:37:13] near-cache entry hit: {username: "zappee", value: 5}
[23:37:14] near-cache entry hit: {username: "zappee", value: 6}
...
The working full code is available here
What I missed here?