Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6ad185e
DOC-4037 add new CSC page
andy-stark-redis Aug 6, 2024
91e332c
DOC-4037 added sequence diagram
andy-stark-redis Aug 7, 2024
51b9348
DOC-4037 add Python guide and other minor content changes
andy-stark-redis Aug 8, 2024
487a51b
DOC-4037 put image files into a subfolder for CSC
andy-stark-redis Aug 8, 2024
2897cc7
DOC-4037 implemented feedback and added Jedis stuff
andy-stark-redis Aug 15, 2024
ce99d38
DOC-4037 updated code samples
andy-stark-redis Sep 13, 2024
2d7302e
Update content/develop/connect/clients/client-side-caching.md
andy-stark-redis Sep 23, 2024
13198e4
Update content/develop/connect/clients/client-side-caching.md
andy-stark-redis Sep 23, 2024
2c54189
Update content/develop/connect/clients/client-side-caching.md
andy-stark-redis Sep 23, 2024
d8ad78e
Update content/develop/connect/clients/python/redis-py.md
andy-stark-redis Sep 23, 2024
df0528a
Update content/develop/connect/clients/client-side-caching.md
andy-stark-redis Sep 23, 2024
df7c8a0
Update content/develop/connect/clients/java/jedis.md
andy-stark-redis Sep 23, 2024
8bca1bb
DOC-4037 removed CSC abbreviation
andy-stark-redis Sep 23, 2024
56b14b5
add link to rsyslog logging
mich-elle-luna Sep 26, 2024
7ebd937
Update READWRITE index.md to fix typo
mich-elle-luna Sep 26, 2024
6e1cce0
Update Uptrace _index.md
mich-elle-luna Sep 26, 2024
6abffb8
Update JSON.STRLEN index.md
mich-elle-luna Sep 26, 2024
cb55e41
Merge pull request #704 from redis/DOC-1595
mich-elle-luna Sep 26, 2024
b49b456
Merge pull request #705 from redis/DOC-4215
mich-elle-luna Sep 26, 2024
d1a9be3
Merge pull request #706 from redis/DOC-3920
mich-elle-luna Sep 26, 2024
a543268
Merge pull request #707 from redis/DOC-2172
mich-elle-luna Sep 26, 2024
c2e6628
Apply suggestions from code review
andy-stark-redis Sep 27, 2024
9c8695b
DOC-4037 implemented PR feedback
andy-stark-redis Sep 27, 2024
9cc4633
Update Jedis version to 5.2.0 (#709)
uglide Sep 27, 2024
84a24e2
DOC-4037 added note about minimum Jedis version
andy-stark-redis Sep 27, 2024
322b346
DOC-4037 added note about minimum Redis version
andy-stark-redis Sep 27, 2024
50c39d8
Merge pull request #530 from redis/DOC-4037-rework-csc-content
andy-stark-redis Sep 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content/commands/json.strlen/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions content/commands/readwrite/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
173 changes: 173 additions & 0 deletions content/develop/connect/clients/client-side-caching.md
Original file line number Diff line number Diff line change
@@ -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.
117 changes: 115 additions & 2 deletions content/develop/connect/clients/java/jedis.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ To include `Jedis` as a dependency in your application, edit the dependency file
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.2</version>
<version>5.2.0</version>
</dependency>
```

Expand All @@ -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'
//...
}
```
Expand Down Expand Up @@ -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
Expand Down
Loading
Loading