Implementing a distributed map

The distributed map is an extension to the Java Map interface. Applications can perform any operation that can be performed on a regular Java map. The data structure internally distributes data across nodes in the cluster. The data is almost evenly distributed among the members and backups can be configured so the data is also replicated. Backups onto multiple cluster members can be configured as synchronous or asynchronous; for synchronous backups when a map.put(key, value) returns, it is guaranteed that the entry is replicated to one other node. Each distribute map is distinguished by the namespace and it is set upon creation of the distributed map. By default, a distributed map has one synchronous and one asynchronous backup copy in the cluster members.

The readBackupData property is supported for the map.get(key) method only.

The Distributed Coordination Service enables applications running on multiple controllers to register listeners to receive notifications for specific distributed map. Notification is sent when an entry in the distributed map is added, updated or removed, except when data is merged when a controller rejoins a controller team. Do not rely on map listener notifications to track data that is being merged from a previously-partitioned controller.

Performance Considerations 

  • Minimize tying map entry listeners to persistence. Consider how important it is for your data to be persisted before automatically tying a distributed map entry listener for the purpose of writing to the database.

  • Minimize other in-memory local caches for distributed map data. The distributed map is already in memory and serves this purpose. If your application needs this data to be available if and when the coordination service is down, then a local cache could be appropriate as well as reading from persistence any previously saved records to startup the cache in those scenarios.

Distributed map

@Component
public class Consumer {
    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY, policy = ReferencePolicy.DYNAMIC)
    private volatile CoordinationService coordinationService;
    private static final Namespace NAMESPACE = Namespace.forReplicatedProcess(Consumer.class);
    private EntryListener<Id<Device, UUID>, Device> deviceListener = new DeviceListener();

    @Activate
    public void activate() {
        DistributedMap<Id<Device, UUID>, Device> map = coordinationService.getMap(NAMESPACE);
        map.register(deviceListener);

        Device device = new Device(...);
        map.put(device.getId(), device);
    }

    @Deactivate
    public void deactivate() {
        DistributedMap<Id<Device, UUID>, Device> map = coordinationService.getMap(NAMESPACE);
        map.unregister(deviceListener);
    }

    private class DeviceListener implements EntryListener<Id<Device, UUID>, Device> {
        @Override
        public void added(EntryEvent<Id<Device, UUID>, Device> entry) {
            Device device = entry.getValue();
        }
        ...
    }
}
More information
Distributed map