diff --git a/content/commands/json.strlen/index.md b/content/commands/json.strlen/index.md index 01c7a30abd..8604e4da77 100644 --- a/content/commands/json.strlen/index.md +++ b/content/commands/json.strlen/index.md @@ -49,7 +49,7 @@ is JSONPath to specify. Default is root `$`, if not provided. Returns null if th ## Return -JSON.STRLEN returns by recursive descent an array of integer replies for each path, the array's length, or `nil`, if the matching JSON value is not a string. +JSON.STRLEN returns by recursive descent an array of integer replies for each path, the string's length, or `nil`, if the matching JSON value is not a string. For more information about replies, see [Redis serialization protocol specification]({{< relref "/develop/reference/protocol-spec" >}}). ## Examples diff --git a/content/commands/readwrite/index.md b/content/commands/readwrite/index.md index 3aea260732..e8d9596a92 100644 --- a/content/commands/readwrite/index.md +++ b/content/commands/readwrite/index.md @@ -18,13 +18,13 @@ command_flags: - stale - fast complexity: O(1) -description: Enables read-write queries for a connection to a Reids Cluster replica +description: Enables read-write queries for a connection to a Redis Cluster replica node. group: cluster hidden: false linkTitle: READWRITE since: 3.0.0 -summary: Enables read-write queries for a connection to a Reids Cluster replica node. +summary: Enables read-write queries for a connection to a Redis Cluster replica node. syntax_fmt: READWRITE syntax_str: '' title: READWRITE diff --git a/content/develop/connect/clients/client-side-caching.md b/content/develop/connect/clients/client-side-caching.md new file mode 100644 index 0000000000..a0fb944a81 --- /dev/null +++ b/content/develop/connect/clients/client-side-caching.md @@ -0,0 +1,173 @@ +--- +categories: +- docs +- develop +- stack +- oss +- rs +- rc +- oss +- kubernetes +- clients +description: Server-assisted, client-side caching in Redis +linkTitle: Client-side caching +title: Client-side caching introduction +weight: 20 +--- + +*Client-side caching* reduces network traffic between +a Redis client and the server, which generally improves performance. +See [Client-side caching compatibility with Redis Software and Redis Cloud]({{< relref "operate/rs/references/compatibility/client-side-caching" >}}) +for details on Redis versions that support client-side caching. + +By default, an [application server](https://en.wikipedia.org/wiki/Application_server) +(which sits between the user app and the database) contacts the +Redis database server through the client library for every read request. +The diagram below shows the flow of communication from the user app, +through the application server to the database and back again: + +{{< image filename="images/csc/CSCNoCache.drawio.svg" >}} + +When you use client-side caching, the client library +maintains a local cache of data items as it retrieves them +from the database. When the same items are needed again, the client +can satisfy the read requests from the cache instead of the database: + +{{< image filename="images/csc/CSCWithCache.drawio.svg" >}} + +Accessing the cache is much faster than communicating with the database over the +network and it reduces network traffic. Client-side caching reduces +the load on the database server, so you may be able to run it using less hardware +resources. + +As with other forms of [caching](https://en.wikipedia.org/wiki/Cache_(computing)), +client-side caching works well in the very common use case where a small subset of the data +is accessed much more frequently than the rest of the data (according +to the [Pareto principle](https://en.wikipedia.org/wiki/Pareto_principle)). + +## Updating the cache when the data changes + +All caching systems must implement a scheme to update data in the cache +when the corresponding data changes in the main database. Redis uses an +approach called *tracking*. + +When client-side caching is enabled, the Redis server remembers or *tracks* the set of keys +that each client connection has previously read. This includes cases where the client +reads data directly, as with the [`GET`]({{< relref "/commands/get" >}}) +command, and also where the server calculates values from the stored data, +as with [`STRLEN`]({{< relref "/commands/strlen" >}}). When any client +writes new data to a tracked key, the server sends an invalidation message +to all clients that have accessed that key previously. This message warns +the clients that their cached copies of the data are no longer valid and the clients +will evict the stale data in response. Next time a client reads from +the same key, it will access the database directly and refresh its cache +with the updated data. + +The sequence diagram below shows how two clients might interact as they +access and update the same key: + +{{< image filename="images/csc/CSCSeqDiagram.drawio.svg" >}} + +## Which commands can cache data? + +All read-only commands (with the `@read` +[ACL category]({{< relref "/operate/oss_and_stack/management/security/acl" >}})) +will use cached data, except for the following: + +- Any commands for + [probabilistic data types]({{< relref "/develop/data-types/probabilistic" >}}). + These types are designed to be updated frequently, which means that caching + has little or no benefit. +- Non-deterministic commands such as [`HGETALL`]({{< relref "/commands/hgetall" >}}), + [`HSCAN`]({{< relref "/commands/hscan" >}}), + and [`ZRANDMEMBER`]({{< relref "/commands/zrandmember" >}}). By design, these commands + give different results each time they are called. +- Search and query commands (with the `FT.*` prefix), such as + [`FT.SEARCH`]({{< baseurl >}}/commands/ft.search). + +You can use the [`MONITOR`]({{< relref "/commands/monitor" >}}) command to +check the server's behavior when you are using client-side caching. Because `MONITOR` only +reports activity from the server, you should find the first cacheable +access to a key causes a response from the server. However, subsequent +accesses are satisfied by the cache, and so `MONITOR` should report no +server activity if client-side caching is working correctly. + +## What data gets cached for a command? + +Broadly speaking, the data from the specific response to a command invocation +gets cached after it is used for the first time. Subsets of that data +or values calculated from it are retrieved from the server as usual and +then cached separately. For example: + +- The whole string retrieved by [`GET`]({{< relref "/commands/get" >}}) + is added to the cache. Parts of the same string retrieved by + [`SUBSTR`]({{< relref "/commands/substr" >}}) are calculated on the + server the first time and then cached separately from the original + string. +- Using [`GETBIT`]({{< relref "/commands/getbit" >}}) or + [`BITFIELD`]({{< relref "/commands/bitfield" >}}) on a string + caches the returned values separately from the original string. +- For composite data types accessed by keys + ([hash]({{< relref "/develop/data-types/hashes" >}}), + [JSON]({{< relref "/develop/data-types/json" >}}), + [set]({{< relref "/develop/data-types/sets" >}}), and + [sorted set]({{< relref "/develop/data-types/sorted-sets" >}})), + the whole object is cached separately from the individual fields. + So the results of `JSON.GET mykey $` and `JSON.GET mykey $.myfield` create + separate entries in the cache. +- Ranges from [lists]({{< relref "/develop/data-types/lists" >}}), + [streams]({{< relref "/develop/data-types/streams" >}}), + and [sorted sets]({{< relref "/develop/data-types/sorted-sets" >}}) + are cached separately from the object they form a part of. Likewise, + subsets returned by [`SINTER`]({{< relref "/commands/sinter" >}}) and + [`SDIFF`]({{< relref "/commands/sdiff" >}}) create separate cache entries. +- For multi-key read commands such as [`MGET`]({{< relref "/commands/mget" >}}), + the ordering of the keys is significant. For example `MGET name:1 name:2` is + cached separately from `MGET name:2 name:1` because the server returns the + values in the order you specify. +- Boolean or numeric values calculated from data types (for example + [`SISMEMBER`]({{< relref "/commands/sismember" >}})) and + [`LLEN`]({{< relref "/commands/llen" >}}) are cached separately from the + object they refer to. + +## Usage recommendations + +Like any caching system, client-side caching has some limitations: + +- The cache has only a limited amount of memory available. When the limit + is reached, the client must *evict* potentially useful items from the + cache to make room for new ones. +- Cache misses, tracking, and invalidation messages always add a slight + performance penalty. + +Below are some guidelines to help you use client-side caching efficiently, within these +limitations: + +- **Use a separate connection for data that is not cache-friendly**: + Caching gives the most benefit + for keys that are read frequently and updated infrequently. However, you + may also have data, such as counters and scoreboards, that receives frequent + updates. In cases like this, the performance overhead of the invalidation + messages can be greater than the savings made by caching. Avoid this problem + by using a separate connection *without* client-side caching for any data that is + not cache-friendly. +- **Estimate how many items you can cache**: The client libraries let you + specify the maximum number of items you want to hold in the cache. You + can calculate an estimate for this number by dividing the + maximum desired size of the + cache in memory by the average size of the items you want to store + (use the [`MEMORY USAGE`]({{< relref "/commands/memory-usage" >}}) + command to get the memory footprint of a key). For example, if you had + 10MB (or 10485760 bytes) available for the cache, and the average + size of an item was 80 bytes, you could fit approximately + 10485760 / 80 = 131072 items in the cache. Monitor memory usage + on your server with a realistic test load to adjust your estimate + up or down. + + ## Reference + + The Redis server implements extra features for client-side caching that are not used by + the main Redis clients, but may be useful for custom clients and other + advanced applications. See + [Client-side caching reference]({{< relref "/develop/reference/client-side-caching" >}}) + for a full technical guide to all the options available for client-side caching. diff --git a/content/develop/connect/clients/java/jedis.md b/content/develop/connect/clients/java/jedis.md index b1465a9c1c..039a1517ca 100644 --- a/content/develop/connect/clients/java/jedis.md +++ b/content/develop/connect/clients/java/jedis.md @@ -33,7 +33,7 @@ To include `Jedis` as a dependency in your application, edit the dependency file redis.clients jedis - 5.1.2 + 5.2.0 ``` @@ -45,7 +45,7 @@ To include `Jedis` as a dependency in your application, edit the dependency file } //... dependencies { - implementation 'redis.clients:jedis:5.1.2' + implementation 'redis.clients:jedis:5.2.0' //... } ``` @@ -196,6 +196,119 @@ public class Main { } ``` +## Connect using client-side caching + +Client-side caching is a technique to reduce network traffic between +the client and server, resulting in better performance. See +[Client-side caching introduction]({{< relref "/develop/connect/clients/client-side-caching" >}}) +for more information about how client-side caching works and how to use it effectively. + +To enable client-side caching, specify the +[RESP3]({{< relref "/develop/reference/protocol-spec#resp-versions" >}}) +protocol and pass a cache configuration object during the connection. + +The example below shows the simplest client-side caching connection to the default host and port, +`localhost:6379`. +All of the connection variants described above accept these parameters, so you can +use client-side caching with a connection pool or a cluster connection in exactly the same way. + +{{< note >}}Client-side caching requires Jedis v5.2.0 or later. +To maximize compatibility with all Redis products, client-side caching +is supported by Redis v7.4 or later. +{{< /note >}} + +```java +HostAndPort endpoint = new HostAndPort("localhost", 6379); + +DefaultJedisClientConfig config = DefaultJedisClientConfig + .builder() + .password("secretPassword") + .protocol(RedisProtocol.RESP3) + .build(); + +CacheConfig cacheConfig = CacheConfig.builder().maxSize(1000).build(); + +UnifiedJedis client = new UnifiedJedis(endpoint, config, cacheConfig); +``` + +Once you have connected, the usual Redis commands will work transparently +with the cache: + +```java +client.set("city", "New York"); +client.get("city"); // Retrieved from Redis server and cached +client.get("city"); // Retrieved from cache +``` + +You can see the cache working if you connect to the same Redis database +with [`redis-cli`]({{< relref "/develop/connect/cli" >}}) and run the +[`MONITOR`]({{< relref "/commands/monitor" >}}) command. If you run the +code above but without passing `cacheConfig` during the connection, +you should see the following in the CLI among the output from `MONITOR`: + +``` +1723109720.268903 [...] "SET" "city" "New York" +1723109720.269681 [...] "GET" "city" +1723109720.270205 [...] "GET" "city" +``` + +The server responds to both `get("city")` calls. +If you run the code with `cacheConfig` added in again, you will see + +``` +1723110248.712663 [...] "SET" "city" "New York" +1723110248.713607 [...] "GET" "city" +``` + +The first `get("city")` call contacted the server, but the second +call was satisfied by the cache. + +### Removing items from the cache + +You can remove individual keys from the cache with the +`deleteByRedisKey()` method of the cache object. This removes all cached items associated +with each specified key, so all results from multi-key commands (such as +[`MGET`]({{< relref "/commands/mget" >}})) and composite data structures +(such as [hashes]({{< relref "/develop/data-types/hashes" >}})) will be +cleared at once. The example below shows the effect of removing a single +key from the cache: + +```java +client.hget("person:1", "name"); // Read from the server +client.hget("person:1", "name"); // Read from the cache + +client.hget("person:2", "name"); // Read from the server +client.hget("person:2", "name"); // Read from the cache + +Cache myCache = client.getCache(); +myCache.deleteByRedisKey("person:1"); + +client.hget("person:1", "name"); // Read from the server +client.hget("person:1", "name"); // Read from the cache + +client.hget("person:2", "name"); // Still read from the cache +``` + +You can also clear all cached items using the `flush()` +method: + +```java +client.hget("person:1", "name"); // Read from the server +client.hget("person:1", "name"); // Read from the cache + +client.hget("person:2", "name"); // Read from the server +client.hget("person:2", "name"); // Read from the cache + +Cache myCache = client.getCache(); +myCache.flush(); + +client.hget("person:1", "name"); // Read from the server +client.hget("person:1", "name"); // Read from the cache + +client.hget("person:2", "name"); // Read from the server +client.hget("person:2", "name"); // Read from the cache +``` + ## Production usage The following sections explain how to handle situations that may occur diff --git a/content/develop/connect/clients/python/redis-py.md b/content/develop/connect/clients/python/redis-py.md index 06c7602362..dec87155d0 100644 --- a/content/develop/connect/clients/python/redis-py.md +++ b/content/develop/connect/clients/python/redis-py.md @@ -119,6 +119,116 @@ r.get('foo') ``` For more information, see [redis-py TLS examples](https://redis-py.readthedocs.io/en/stable/examples/ssl_connection_examples.html). +## Connect using client-side caching + +Client-side caching is a technique to reduce network traffic between +the client and server, resulting in better performance. See +[Client-side caching introduction]({{< relref "/develop/connect/clients/client-side-caching" >}}) +for more information about how client-side caching works and how to use it effectively. + +To enable client-side caching, add some extra parameters when you connect +to the server: + +- `protocol`: (Required) You must pass a value of `3` here because + client-side caching requires the [RESP3]({{< relref "/develop/reference/protocol-spec#resp-versions" >}}) + protocol. +- `cache_config`: (Required) Pass `cache_config=CacheConfig()` here to enable client-side caching. + +The example below shows the simplest client-side caching connection to the default host and port, +`localhost:6379`. +All of the connection variants described above accept these parameters, so you can +use client-side caching with a connection pool or a cluster connection in exactly the same way. + +{{< note >}}Client-side caching requires redis-py v5.1.0 or later. +To maximize compatibility with all Redis products, client-side caching +is supported by Redis v7.4 or later. +{{< /note >}} + +```python +import redis +from redis.cache import CacheConfig + +r = redis.Redis( + protocol=3, + cache_config=CacheConfig(), + decode_responses=True +) + +r.set("city", "New York") +cityNameAttempt1 = r.get("city") # Retrieved from Redis server and cached +cityNameAttempt2 = r.get("city") # Retrieved from cache +``` + +You can see the cache working if you connect to the same Redis database +with [`redis-cli`]({{< relref "/develop/connect/cli" >}}) and run the +[`MONITOR`]({{< relref "/commands/monitor" >}}) command. If you run the +code above with the `cache_config` line commented out, you should see +the following in the CLI among the output from `MONITOR`: + +``` +1723109720.268903 [...] "SET" "city" "New York" +1723109720.269681 [...] "GET" "city" +1723109720.270205 [...] "GET" "city" +``` + +The server responds to both `get("city")` calls. +If you run the code again with `cache_config` uncommented, you will see + +``` +1723110248.712663 [...] "SET" "city" "New York" +1723110248.713607 [...] "GET" "city" +``` + +The first `get("city")` call contacted the server but the second +call was satisfied by the cache. + +### Removing items from the cache + +You can remove individual keys from the cache with the +`delete_by_redis_keys()` method. This removes all cached items associated +with the keys, so all results from multi-key commands (such as +[`MGET`]({{< relref "/commands/mget" >}})) and composite data structures +(such as [hashes]({{< relref "/develop/data-types/hashes" >}})) will be +cleared at once. The example below shows the effect of removing a single +key from the cache: + +```python +r.hget("person:1", "name") # Read from the server +r.hget("person:1", "name") # Read from the cache + +r.hget("person:2", "name") # Read from the server +r.hget("person:2", "name") # Read from the cache + +cache = r.get_cache() +cache.delete_by_redis_keys(["person:1"]) + +r.hget("person:1", "name") # Read from the server +r.hget("person:1", "name") # Read from the cache + +r.hget("person:2", "name") # Still read from the cache +``` + +You can also clear all cached items using the `flush()` +method: + +```python +r.hget("person:1", "name") # Read from the server +r.hget("person:1", "name") # Read from the cache + +r.hget("person:2", "name") # Read from the cache +r.hget("person:2", "name") # Read from the cache + +cache = r.get_cache() +cache.flush() + +r.hget("person:1", "name") # Read from the server +r.hget("person:1", "name") # Read from the cache + +r.hget("person:2", "name") # Read from the server +r.hget("person:2", "name") # Read from the cache +``` + + ## Example: Indexing and querying JSON documents Make sure that you have Redis Stack and `redis-py` installed. Import dependencies: diff --git a/content/develop/use/client-side-caching.md b/content/develop/reference/client-side-caching.md similarity index 98% rename from content/develop/use/client-side-caching.md rename to content/develop/reference/client-side-caching.md index 224adc7f8f..c8fe2dd0a9 100644 --- a/content/develop/use/client-side-caching.md +++ b/content/develop/reference/client-side-caching.md @@ -13,10 +13,17 @@ description: 'Server-assisted, client-side caching in Redis ' linkTitle: Client-side caching -title: Client-side caching in Redis +title: Client-side caching reference +aliases: /develop/use/client-side-caching/ weight: 2 --- +{{}}This document is intended as an in-depth reference for +client-side caching. See +[Client-side caching introduction]({{< relref "/develop/connect/clients/client-side-caching" >}}) +for general usage guidelines. +{{}} + Client-side caching is a technique used to create high performance services. It exploits the memory available on application servers, servers that are usually distinct computers compared to the database nodes, to store some subset diff --git a/content/integrate/uptrace-with-redis-enterprise/_index.md b/content/integrate/uptrace-with-redis-enterprise/_index.md index b86422c4b1..6c2769f2d6 100644 --- a/content/integrate/uptrace-with-redis-enterprise/_index.md +++ b/content/integrate/uptrace-with-redis-enterprise/_index.md @@ -17,8 +17,6 @@ type: integration weight: 7 --- -To collect, view, and monitor metrics data from your databases and other cluster components, you can connect Uptrace to your Redis Enterprise cluster using OpenTelemetry Collector. - Uptrace is an [open source APM tool](https://uptrace.dev/get/open-source-apm.html) that supports distributed tracing, metrics, and logs. You can use it to monitor applications and set up automatic alerts to receive notifications. Uptrace uses OpenTelemetry to collect and export telemetry data from software applications such as Redis. OpenTelemetry is an open source observability framework that aims to provide a single standard for all types of observability signals such as traces, metrics, and logs. diff --git a/content/operate/rs/clusters/logging/log-security.md b/content/operate/rs/clusters/logging/log-security.md index 7f17985d23..6ba7e715aa 100644 --- a/content/operate/rs/clusters/logging/log-security.md +++ b/content/operate/rs/clusters/logging/log-security.md @@ -15,7 +15,7 @@ Redis Enterprise comes with [a set of logs]({{< relref "/operate/rs/clusters/log Redis Enterprise sends logs to syslog by default. You can send these logs to a remote logging server by configuring syslog. -To do this, modify the syslog or rsyslog configuration on your operating system to send logs in the `$logdir` directory (`/var/opt/redislabs/log` in default installations) to a remote monitoring server of your choice. +To do this, modify the syslog or rsyslog configuration on your operating system to send logs in the `$logdir` directory (`/var/opt/redislabs/log` in default installations) to a remote monitoring server of your choice. See [rsyslog logging]({{< relref "/operate/rs/clusters/logging/rsyslog-logging/" >}}) for additional details. ## Log rotation diff --git a/static/images/csc/CSCNoCache.drawio.svg b/static/images/csc/CSCNoCache.drawio.svg new file mode 100644 index 0000000000..9c07350368 --- /dev/null +++ b/static/images/csc/CSCNoCache.drawio.svg @@ -0,0 +1,4 @@ + + + +
App
App
Application server
Application server
App
backend
App...
Redis
client
Redis...
Read request
Read request
Response
Response
Text is not SVG - cannot display
\ No newline at end of file diff --git a/static/images/csc/CSCSeqDiagram.drawio.svg b/static/images/csc/CSCSeqDiagram.drawio.svg new file mode 100644 index 0000000000..744fc59b7c --- /dev/null +++ b/static/images/csc/CSCSeqDiagram.drawio.svg @@ -0,0 +1,4 @@ + + + +
Client A cache
Client A cache
Client A
Client A
Redis database
Redis database
DB tracks Client A
D...
DB tracks Client B
D...
Client B
Client B
Client B cache
Client B cache
SET city Paris
SET city Pa...
GET city
GET city
"Paris"
"Paris"
CACHE city Paris
CACHE city...
"Not cached"
"Not cached"
GET city
GET city
GET city
GET city
"Not cached"
"Not cached"
GET city
GET city
"Paris"
"Paris"
CACHE city Paris
CACHE city...
SET city Berlin
SET city Be...
INVALIDATE city
INVALIDATE...
INVALIDATE city
INVALIDATE...
DELETE city
DELETE city
DELETE city
DELETE city
GET city
GET city
"Not cached"
"Not cached"
GET city
GET city
"Berlin"
"Berlin"
CACHE city Berlin
CACHE city...
GET city
GET city
"Berlin"
"Berlin"
Text is not SVG - cannot display
\ No newline at end of file diff --git a/static/images/csc/CSCWithCache.drawio.svg b/static/images/csc/CSCWithCache.drawio.svg new file mode 100644 index 0000000000..5f0349967e --- /dev/null +++ b/static/images/csc/CSCWithCache.drawio.svg @@ -0,0 +1,4 @@ + + + +
App
App
Application server
Application server
App
backend
App...
Redis
client
Redis...
Cache
Cache
Read request
Read request
Response
Response
Reduced
network
traffic
Reduced...
Lower latency
Lower latency
Text is not SVG - cannot display
\ No newline at end of file