diff --git a/src/main/asciidoc/reference/redis-cache.adoc b/src/main/asciidoc/reference/redis-cache.adoc new file mode 100644 index 000000000..522b5881b --- /dev/null +++ b/src/main/asciidoc/reference/redis-cache.adoc @@ -0,0 +1,128 @@ +[[redis:support:cache-abstraction]] +== Redis Cache + +NOTE: Changed in 2.0 + +Spring Redis provides an implementation for the Spring https://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/integration.html#cache[cache abstraction] through the `org.springframework.data.redis.cache` package. To use Redis as a backing implementation, add `RedisCacheManager` to your configuration, as follows: + +[source,java] +---- +@Bean +public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { + return RedisCacheManager.create(connectionFactory); +} +---- + +`RedisCacheManager` behavior can be configured with `RedisCacheManagerBuilder`, letting you set the default `RedisCacheConfiguration`, transaction behavior, and predefined caches. + +[source,java] +---- +RedisCacheManager cm = RedisCacheManager.builder(connectionFactory) + .cacheDefaults(defaultCacheConfig()) + .withInitialCacheConfigurations(singletonMap("predefined", defaultCacheConfig().disableCachingNullValues())) + .transactionAware() + .build(); +---- + +As shown in the preceding example, `RedisCacheManager` allows definition of configurations on a per-cache basis. + +The behavior of `RedisCache` created with `RedisCacheManager` is defined with `RedisCacheConfiguration`. The configuration lets you set key expiration times, prefixes, and ``RedisSerializer`` implementations for converting to and from the binary storage format, as shown in the following example: + +[source,java] +---- +RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofSeconds(1)) + .disableCachingNullValues(); +---- + +`RedisCacheManager` defaults to a lock-free `RedisCacheWriter` for reading and writing binary values. Lock-free caching improves throughput. The lack of entry locking can lead to overlapping, non-atomic commands for the `putIfAbsent` and `clean` methods, as those require multiple commands to be sent to Redis. The locking counterpart prevents command overlap by setting an explicit lock key and checking against presence of this key, which leads to additional requests and potential command wait times. + +It is possible to opt in to the locking behavior as follows: + +[source,java] +---- +RedisCacheManager cm = RedisCacheManager.build(RedisCacheWriter.lockingRedisCacheWriter(connectionFactory)) + .cacheDefaults(defaultCacheConfig()) + ... +---- + +By default, any `key` for a cache entry gets prefixed with the actual cache name followed by two colons. +This behavior can be changed to a static as well as a computed prefix. + +The following example shows how to set a static prefix: + +[source,java] +---- +// static key prefix +RedisCacheConfiguration.defaultCacheConfig().prefixKeysWith("( ͡° ᴥ ͡°)"); + +The following example shows how to set a computed prefix: + +// computed key prefix +RedisCacheConfiguration.defaultCacheConfig().computePrefixWith(cacheName -> "¯\_(ツ)_/¯" + cacheName); +---- + +The cache implementation defaults to use `KEYS` and `DEL` to clear the cache. `KEYS` can cause performance issues with large keyspaces. Therefore, the default `RedisCacheWriter` can be created with a `BatchStrategy` to switch to a `SCAN`-based batch strategy. The `SCAN` strategy requires a batch size to avoid excessive Redis command roundtrips: + +[source,java] +---- +RedisCacheManager cm = RedisCacheManager.build(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory, BatchStrategy.scan(1000))) + .cacheDefaults(defaultCacheConfig()) + ... +---- + +NOTE: The `KEYS` batch strategy is fully supported using any driver and Redis operation mode (Standalone, Clustered). `SCAN` is fully supported when using the Lettuce driver. Jedis supports `SCAN` only in non-clustered modes. + +The following table lists the default settings for `RedisCacheManager`: + +.`RedisCacheManager` defaults +[width="80%",cols="<1,<2",options="header"] +|==== +|Setting +|Value + +|Cache Writer +|Non-locking, `KEYS` batch strategy + +|Cache Configuration +|`RedisCacheConfiguration#defaultConfiguration` + +|Initial Caches +|None + +|Transaction Aware +|No +|==== + +The following table lists the default settings for `RedisCacheConfiguration`: + +.RedisCacheConfiguration defaults +[width="80%",cols="<1,<2",options="header"] +|==== +|Key Expiration +|None + +|Cache `null` +|Yes + +|Prefix Keys +|Yes + +|Default Prefix +|The actual cache name + +|Key Serializer +|`StringRedisSerializer` + +|Value Serializer +|`JdkSerializationRedisSerializer` + +|Conversion Service +|`DefaultFormattingConversionService` with default cache key converters +|==== + +[NOTE] +==== +By default `RedisCache`, statistics are disabled. +Use `RedisCacheManagerBuilder.enableStatistics()` to collect local _hits_ and _misses_ through `RedisCache#getStatistics()`, returning a snapshot of the collected data. +==== diff --git a/src/main/asciidoc/reference/redis.adoc b/src/main/asciidoc/reference/redis.adoc index 58961879b..691e101a6 100644 --- a/src/main/asciidoc/reference/redis.adoc +++ b/src/main/asciidoc/reference/redis.adoc @@ -652,6 +652,8 @@ include::{referenceDir}/pipelining.adoc[] include::{referenceDir}/redis-scripting.adoc[] +include::{referenceDir}/redis-cache.adoc[] + :leveloffset: 1 [[redis:support]] == Support Classes @@ -693,120 +695,3 @@ public class AnotherExample { As shown in the preceding example, the consuming code is decoupled from the actual storage implementation. In fact, there is no indication that Redis is used underneath. This makes moving from development to production environments transparent and highly increases testability (the Redis implementation can be replaced with an in-memory one). -[[redis:support:cache-abstraction]] -=== Support for the Spring Cache Abstraction - -NOTE: Changed in 2.0 - -Spring Redis provides an implementation for the Spring https://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/integration.html#cache[cache abstraction] through the `org.springframework.data.redis.cache` package. To use Redis as a backing implementation, add `RedisCacheManager` to your configuration, as follows: - -[source,java] ----- -@Bean -public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { - return RedisCacheManager.create(connectionFactory); -} ----- - -`RedisCacheManager` behavior can be configured with `RedisCacheManagerBuilder`, letting you set the default `RedisCacheConfiguration`, transaction behavior, and predefined caches. - -[source,java] ----- -RedisCacheManager cm = RedisCacheManager.builder(connectionFactory) - .cacheDefaults(defaultCacheConfig()) - .withInitialCacheConfigurations(singletonMap("predefined", defaultCacheConfig().disableCachingNullValues())) - .transactionAware() - .build(); ----- - -As shown in the preceding example, `RedisCacheManager` allows definition of configurations on a per-cache basis. - -The behavior of `RedisCache` created with `RedisCacheManager` is defined with `RedisCacheConfiguration`. The configuration lets you set key expiration times, prefixes, and ``RedisSerializer`` implementations for converting to and from the binary storage format, as shown in the following example: - -[source,java] ----- -RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() - .entryTtl(Duration.ofSeconds(1)) - .disableCachingNullValues(); ----- - -`RedisCacheManager` defaults to a lock-free `RedisCacheWriter` for reading and writing binary values. Lock-free caching improves throughput. The lack of entry locking can lead to overlapping, non-atomic commands for the `putIfAbsent` and `clean` methods, as those require multiple commands to be sent to Redis. The locking counterpart prevents command overlap by setting an explicit lock key and checking against presence of this key, which leads to additional requests and potential command wait times. - -It is possible to opt in to the locking behavior as follows: - -[source,java] ----- -RedisCacheManager cm = RedisCacheManager.build(RedisCacheWriter.lockingRedisCacheWriter()) - .cacheDefaults(defaultCacheConfig()) - ... ----- - -By default, any `key` for a cache entry gets prefixed with the actual cache name followed by two colons. -This behavior can be changed to a static as well as a computed prefix. - -The following example shows how to set a static prefix: - -[source,java] ----- -// static key prefix -RedisCacheConfiguration.defaultCacheConfig().prefixKeysWith("( ͡° ᴥ ͡°)"); - -The following example shows how to set a computed prefix: - -// computed key prefix -RedisCacheConfiguration.defaultCacheConfig().computePrefixWith(cacheName -> "¯\_(ツ)_/¯" + cacheName); ----- - -The following table lists the default settings for `RedisCacheManager`: - -.`RedisCacheManager` defaults -[width="80%",cols="<1,<2",options="header"] -|==== -|Setting -|Value - -|Cache Writer -|Non-locking - -|Cache Configuration -|`RedisCacheConfiguration#defaultConfiguration` - -|Initial Caches -|None - -|Transaction Aware -|No -|==== - -The following table lists the default settings for `RedisCacheConfiguration`: - -.RedisCacheConfiguration defaults -[width="80%",cols="<1,<2",options="header"] -|==== -|Key Expiration -|None - -|Cache `null` -|Yes - -|Prefix Keys -|Yes - -|Default Prefix -|The actual cache name - -|Key Serializer -|`StringRedisSerializer` - -|Value Serializer -|`JdkSerializationRedisSerializer` - -|Conversion Service -|`DefaultFormattingConversionService` with default cache key converters -|==== - -[NOTE] -==== -By default `RedisCache`, statistics are disabled. -Use `RedisCacheManagerBuilder.enableStatistics()` to collect local _hits_ and _misses_ through `RedisCache#getStatistics()`, returning a snapshot of the collected data. -==== diff --git a/src/main/java/org/springframework/data/redis/cache/BatchStrategy.java b/src/main/java/org/springframework/data/redis/cache/BatchStrategy.java index 5bf25537e..9c41f6c80 100644 --- a/src/main/java/org/springframework/data/redis/cache/BatchStrategy.java +++ b/src/main/java/org/springframework/data/redis/cache/BatchStrategy.java @@ -39,8 +39,8 @@ public abstract class BatchStrategy { /** * Batching strategy using a single {@code KEYS} and {@code DEL} command to remove all matching keys. {@code KEYS} - * scans the entire keyspace of the Redis database and can block the Redis worker thread for a long time when the - * keyspace has a significant size. + * scans the entire keyspace of the Redis database and can block the Redis worker thread for a long time on large + * keyspaces. *

* {@code KEYS} is supported for standalone and clustered (sharded) Redis operation modes. * diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java b/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java index bd764f5d2..766e83138 100644 --- a/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java +++ b/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java @@ -169,6 +169,8 @@ public class RedisCacheManager extends AbstractTransactionSupportingCacheManager *

*
locking
*
disabled
+ *
batch strategy
+ *
{@link BatchStrategy#keys() KEYS}
*
cache configuration
*
{@link RedisCacheConfiguration#defaultCacheConfig()}
*
initial caches