You are viewing the documentation for Blueriq 17. Documentation for other versions is available in our documentation directory.
Redis Key-Value Store Component
Prerequisites
An instance of Redis server needs to run on a node and needs to be accessible from the Blueriq Runtime.
Depending on the linux distribution, a Redis package may be available from the repository in any case consult their official documentation here.
Redis does not officially support Windows. However, the Microsoft Open Tech group develops and maintains this Windows port targeting Win64. More information here.
Enable/Disable
In order to enable the component, the profile "keyvalue-redis-store" profile must be added in the bootstrap.properties
spring.profiles.active=native,keyvalue-redis-store
Properties
The Redis Key-Value Store Component defines the following properties used for 10. Concurrency Control on Multiple Nodes [editor]:
Property | Description | Required | Default Value |
---|---|---|---|
blueriq.keyvalue-redis-store.subscription-pool.type | The thread pool type to use for the keyspace notifications subscription thread pool. | FALSE | CACHED |
blueriq.keyvalue-redis-store.subscription-pool.thread-name-prefix | The thread name prefix used for threads in the keyspace notifications subscription thread pool. | FALSE | keyspace-subscription- |
blueriq.keyvalue-redis-store.subscription-pool.thread-count | Indicates how many threads should be created when using FIXED thread pools. | FALSE | 0 |
blueriq.keyvalue-redis-store.task-pool.type | The thread pool type to use for the keyspace notifications task thread pool. | FALSE | FIXED |
blueriq.keyvalue-redis-store.task-pool.thread-name-prefix | The thread name prefix used for threads in the keyspace notifications subscription thread pool. | FALSE | keyspace-task- |
blueriq.keyvalue-redis-store.task-pool.thread-count | Indicates how many threads should be created when using FIXED thread pools. | FALSE | 4 |
The Redis Key-Value Store Component uses the following default Spring Boot properties in order to connect to Redis:
Property | Description | Required | Default Value |
---|---|---|---|
spring.redis.host | The DNS name or IP address of the Redis server | TRUE | |
spring.redis.port | The port on which to connect to Redis | FALSE | 6379 |
spring.redis.password | The password used to connect to Redis. Can be left empty if no password is required. | FALSE |
The following example configuration connects the Runtime to a Redis instance running on localhost on the default port and using a password:
spring.redis.host=localhost spring.redis.password=example
Using the key-value store in custom plug-ins
Blueriq provides an IKeyValueStore interface which can be used to interact with a generic key-value store. In order to use this interface, add blueriq-component-api to your project's dependencies:
<dependency> <groupId>com.blueriq</groupId> <artifactId>blueriq-component-api</artifactId> <version>${blueriq.version}</version> </dependency>
Then, inject the IKeyValueStore in your components:
@Component public class ExampleComponent { private final IKeyValueStore keyValueStore; public ExampleComponent(IKeyValueStore keyValueStore) { this.keyValueStore = keyValueStore; } public void operation() { keyValueStore.set(namespacedKey("key"), "value"); } private String namespacedKey(String key) { return "example" + keyValueStore.getNamespaceSeparator() + key; } }
Note that we recommend using namespaces for your keys, in order to keep them separate from keys used by Blueriq or Spring Session. The root namespace used by Blueriq is "blueriq". The root namespace used by Spring Session is "spring".
If you would like to hide the namespace logic, the NamespacedKeyValueStore implementation may be used, available in the blueriq-runtime artifact. The code example below writes the same "example:key" key in the key-value store, but without having to explicitly prefix the key with a namespace every time:
@Component public class ExampleComponent { private final IKeyValueStore keyValueStore; public ExampleComponent(IKeyValueStore keyValueStore) { this.keyValueStore = new NamespacedKeyValueStore(keyValueStore, "example"); } public void operation() { keyValueStore.set("key", "value"); } }
Using other key-value store implementations
It is possible to replace the default Redis-based key-value store implementation with an implementation that uses another type of key-value store. This section shows as an example how to use Hazelcast as a key-value store and session store.
Create project and add dependencies
Create a maven project and add hazelcast and blueriq-component-api to your project's dependencies.
<project ...> ... <dependencies> <dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast-all</artifactId> <version>...</version> </dependency> <dependency> <groupId>com.blueriq</groupId> <artifactId>blueriq-component-api</artifactId> <version>...</version> </dependency> </dependencies> </project>
Implement IKeyValueStore
Implement the IKeyValueStore interface. The following example skims over the details but highlights some important issues:
import com.blueriq.component.api.store.keyvalue.IKeyValueStore; // other imports public class HazelcastKeyValueStore implements IKeyValueStore { private IMap<String, Serializable> hazelcastMap; public KeyValueHazelcastStore(IMap<String, Serializable> hazelcastMap) { this.hazelcastMap = hazelcastMap; } @Override public void set(String key, Serializable value) { notNull(key, "Key is required"); try { hazelcastMap.set(key, value); } catch (Exception ex) { throw new KeyValueStoreException(ex); } } @Override public <T extends Serializable> T get(String key, Class<T> valueType) { notNull(key, "Key is required"); notNull(valueType, "Value type is required"); try { Serializable storedValue = hazelcastMap.get(key); if (storedValue == null) { return null; } if (!valueType.isInstance(storedValue)) { throw new IllegalArgumentException("Cannot cast from " + storedValue.getClass() + " to " + valueType); } return valueType.cast(storedValue); } catch (Exception ex) { throw new KeyValueStoreException(ex); } } @Override public IKeyIterator keyIterator(IKeyPattern pattern) { try { if (pattern == null) { return new KeyIterator(hazelcastMap.keySet()); } Predicate<?, ?> keyPredicate = new SqlPredicate(pattern.toString()); Set<String> keys = hazelcastMap.keySet(keyPredicate); return new KeyIterator(keys); } catch (Exception ex) { throw new KeyValueStoreException(ex); } } public IKeyPatternBuilder getKeyPatternBuilder() { return new HazelcastKeyPatternBuilder(); } private static class KeyIterator implements IKeyIterator { private final Iterator<String> hazelcastKeyIterator; public KeyIterator(Set<String> keys) { this.hazelcastKeyIterator = keys.iterator(); } @Override public boolean hasNext() { return hazelcastKeyIterator.hasNext(); } @Override public String next() { return hazelcastKeyIterator.next(); } @Override public void remove() { hazelcastKeyIterator.remove(); } @Override public void close() throws KeyValueStoreException { // this iterator doesn't needs to be closed } } }
Previous: 2. About the load balancer
Next: 4. Cluster configuration